From 41716952f1d0508fb621cb5fec31406d3bd96192 Mon Sep 17 00:00:00 2001 From: Bart Polot Date: Wed, 7 May 2014 12:07:16 +0000 Subject: Renamed directory --- src/cadet/Makefile.am | 194 ++ src/cadet/beautify_log.sh | 18 + src/cadet/cadet.h | 351 +++ src/cadet/cadet_api.c | 2141 ++++++++++++++++++ src/cadet/cadet_common.c | 348 +++ src/cadet/cadet_path.c | 213 ++ src/cadet/cadet_path.h | 185 ++ src/cadet/cadet_protocol.h | 459 ++++ src/cadet/cadet_test_lib.c | 295 +++ src/cadet/cadet_test_lib.h | 106 + src/cadet/cadet_tunnel_tree.c | 1174 ++++++++++ src/cadet/cadet_tunnel_tree.h | 382 ++++ src/cadet/gnunet-cadet-profiler.c | 1092 +++++++++ src/cadet/gnunet-cadet.c | 851 +++++++ src/cadet/gnunet-service-cadet.c | 181 ++ src/cadet/gnunet-service-cadet_channel.c | 2432 ++++++++++++++++++++ src/cadet/gnunet-service-cadet_channel.h | 349 +++ src/cadet/gnunet-service-cadet_connection.c | 3176 +++++++++++++++++++++++++++ src/cadet/gnunet-service-cadet_connection.h | 566 +++++ src/cadet/gnunet-service-cadet_dht.c | 423 ++++ src/cadet/gnunet-service-cadet_dht.h | 92 + src/cadet/gnunet-service-cadet_hello.c | 198 ++ src/cadet/gnunet-service-cadet_hello.h | 76 + src/cadet/gnunet-service-cadet_local.c | 1242 +++++++++++ src/cadet/gnunet-service-cadet_local.h | 226 ++ src/cadet/gnunet-service-cadet_peer.c | 2219 +++++++++++++++++++ src/cadet/gnunet-service-cadet_peer.h | 418 ++++ src/cadet/gnunet-service-cadet_tunnel.c | 2887 ++++++++++++++++++++++++ src/cadet/gnunet-service-cadet_tunnel.h | 531 +++++ src/cadet/loopcheck.sh | 8 + src/cadet/mesh.conf.in | 21 + src/cadet/profiler.conf | 19 + src/cadet/run_profiler.sh | 25 + src/cadet/small.dat | 21 + src/cadet/test_cadet.c | 953 ++++++++ src/cadet/test_cadet.conf | 100 + src/cadet/test_cadet_drop.conf | 4 + src/cadet/test_cadet_local.c | 337 +++ src/cadet/test_cadet_single.c | 329 +++ src/cadet/valgrind-mesh.supp | 116 + src/mesh/Makefile.am | 194 -- src/mesh/beautify_log.sh | 18 - src/mesh/cadet.h | 351 --- src/mesh/cadet_api.c | 2141 ------------------ src/mesh/cadet_common.c | 348 --- src/mesh/cadet_path.c | 213 -- src/mesh/cadet_path.h | 185 -- src/mesh/cadet_protocol.h | 459 ---- src/mesh/cadet_test_lib.c | 295 --- src/mesh/cadet_test_lib.h | 106 - src/mesh/cadet_tunnel_tree.c | 1174 ---------- src/mesh/cadet_tunnel_tree.h | 382 ---- src/mesh/gnunet-cadet-profiler.c | 1092 --------- src/mesh/gnunet-cadet.c | 851 ------- src/mesh/gnunet-service-cadet.c | 181 -- src/mesh/gnunet-service-cadet_channel.c | 2432 -------------------- src/mesh/gnunet-service-cadet_channel.h | 349 --- src/mesh/gnunet-service-cadet_connection.c | 3176 --------------------------- src/mesh/gnunet-service-cadet_connection.h | 566 ----- src/mesh/gnunet-service-cadet_dht.c | 423 ---- src/mesh/gnunet-service-cadet_dht.h | 92 - src/mesh/gnunet-service-cadet_hello.c | 198 -- src/mesh/gnunet-service-cadet_hello.h | 76 - src/mesh/gnunet-service-cadet_local.c | 1242 ----------- src/mesh/gnunet-service-cadet_local.h | 226 -- src/mesh/gnunet-service-cadet_peer.c | 2219 ------------------- src/mesh/gnunet-service-cadet_peer.h | 418 ---- src/mesh/gnunet-service-cadet_tunnel.c | 2887 ------------------------ src/mesh/gnunet-service-cadet_tunnel.h | 531 ----- src/mesh/loopcheck.sh | 8 - src/mesh/mesh.conf.in | 21 - src/mesh/profiler.conf | 19 - src/mesh/run_profiler.sh | 25 - src/mesh/small.dat | 21 - src/mesh/test_cadet.c | 953 -------- src/mesh/test_cadet.conf | 100 - src/mesh/test_cadet_drop.conf | 4 - src/mesh/test_cadet_local.c | 337 --- src/mesh/test_cadet_single.c | 329 --- src/mesh/valgrind-mesh.supp | 116 - 80 files changed, 24758 insertions(+), 24758 deletions(-) create mode 100644 src/cadet/Makefile.am create mode 100755 src/cadet/beautify_log.sh create mode 100644 src/cadet/cadet.h create mode 100644 src/cadet/cadet_api.c create mode 100644 src/cadet/cadet_common.c create mode 100644 src/cadet/cadet_path.c create mode 100644 src/cadet/cadet_path.h create mode 100644 src/cadet/cadet_protocol.h create mode 100644 src/cadet/cadet_test_lib.c create mode 100644 src/cadet/cadet_test_lib.h create mode 100644 src/cadet/cadet_tunnel_tree.c create mode 100644 src/cadet/cadet_tunnel_tree.h create mode 100644 src/cadet/gnunet-cadet-profiler.c create mode 100644 src/cadet/gnunet-cadet.c create mode 100644 src/cadet/gnunet-service-cadet.c create mode 100644 src/cadet/gnunet-service-cadet_channel.c create mode 100644 src/cadet/gnunet-service-cadet_channel.h create mode 100644 src/cadet/gnunet-service-cadet_connection.c create mode 100644 src/cadet/gnunet-service-cadet_connection.h create mode 100644 src/cadet/gnunet-service-cadet_dht.c create mode 100644 src/cadet/gnunet-service-cadet_dht.h create mode 100644 src/cadet/gnunet-service-cadet_hello.c create mode 100644 src/cadet/gnunet-service-cadet_hello.h create mode 100644 src/cadet/gnunet-service-cadet_local.c create mode 100644 src/cadet/gnunet-service-cadet_local.h create mode 100644 src/cadet/gnunet-service-cadet_peer.c create mode 100644 src/cadet/gnunet-service-cadet_peer.h create mode 100644 src/cadet/gnunet-service-cadet_tunnel.c create mode 100644 src/cadet/gnunet-service-cadet_tunnel.h create mode 100755 src/cadet/loopcheck.sh create mode 100644 src/cadet/mesh.conf.in create mode 100644 src/cadet/profiler.conf create mode 100755 src/cadet/run_profiler.sh create mode 100644 src/cadet/small.dat create mode 100644 src/cadet/test_cadet.c create mode 100644 src/cadet/test_cadet.conf create mode 100644 src/cadet/test_cadet_drop.conf create mode 100644 src/cadet/test_cadet_local.c create mode 100644 src/cadet/test_cadet_single.c create mode 100644 src/cadet/valgrind-mesh.supp delete mode 100644 src/mesh/Makefile.am delete mode 100755 src/mesh/beautify_log.sh delete mode 100644 src/mesh/cadet.h delete mode 100644 src/mesh/cadet_api.c delete mode 100644 src/mesh/cadet_common.c delete mode 100644 src/mesh/cadet_path.c delete mode 100644 src/mesh/cadet_path.h delete mode 100644 src/mesh/cadet_protocol.h delete mode 100644 src/mesh/cadet_test_lib.c delete mode 100644 src/mesh/cadet_test_lib.h delete mode 100644 src/mesh/cadet_tunnel_tree.c delete mode 100644 src/mesh/cadet_tunnel_tree.h delete mode 100644 src/mesh/gnunet-cadet-profiler.c delete mode 100644 src/mesh/gnunet-cadet.c delete mode 100644 src/mesh/gnunet-service-cadet.c delete mode 100644 src/mesh/gnunet-service-cadet_channel.c delete mode 100644 src/mesh/gnunet-service-cadet_channel.h delete mode 100644 src/mesh/gnunet-service-cadet_connection.c delete mode 100644 src/mesh/gnunet-service-cadet_connection.h delete mode 100644 src/mesh/gnunet-service-cadet_dht.c delete mode 100644 src/mesh/gnunet-service-cadet_dht.h delete mode 100644 src/mesh/gnunet-service-cadet_hello.c delete mode 100644 src/mesh/gnunet-service-cadet_hello.h delete mode 100644 src/mesh/gnunet-service-cadet_local.c delete mode 100644 src/mesh/gnunet-service-cadet_local.h delete mode 100644 src/mesh/gnunet-service-cadet_peer.c delete mode 100644 src/mesh/gnunet-service-cadet_peer.h delete mode 100644 src/mesh/gnunet-service-cadet_tunnel.c delete mode 100644 src/mesh/gnunet-service-cadet_tunnel.h delete mode 100755 src/mesh/loopcheck.sh delete mode 100644 src/mesh/mesh.conf.in delete mode 100644 src/mesh/profiler.conf delete mode 100755 src/mesh/run_profiler.sh delete mode 100644 src/mesh/small.dat delete mode 100644 src/mesh/test_cadet.c delete mode 100644 src/mesh/test_cadet.conf delete mode 100644 src/mesh/test_cadet_drop.conf delete mode 100644 src/mesh/test_cadet_local.c delete mode 100644 src/mesh/test_cadet_single.c delete mode 100644 src/mesh/valgrind-mesh.supp (limited to 'src') diff --git a/src/cadet/Makefile.am b/src/cadet/Makefile.am new file mode 100644 index 000000000..e9aaec402 --- /dev/null +++ b/src/cadet/Makefile.am @@ -0,0 +1,194 @@ +AM_CPPFLAGS = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +pkgcfgdir= $(pkgdatadir)/config.d/ + +libexecdir= $(pkglibdir)/libexec/ + +pkgcfg_DATA = \ + cadet.conf + +plugindir = $(libdir)/gnunet + +AM_CLFAGS = -g + +libexec_PROGRAMS = \ + gnunet-service-cadet $(EXP_LIBEXEC) + +bin_PROGRAMS = \ + gnunet-cadet + +lib_LTLIBRARIES = \ + libgnunetcadet.la $(EXP_LIB) + +libgnunetcadet_la_SOURCES = \ + cadet_api.c cadet_common.c +libgnunetcadet_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(XLIB) \ + $(LTLIBINTL) +libgnunetcadet_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 5:0:0 + +gnunet_cadet_SOURCES = \ + gnunet-cadet.c +gnunet_cadet_LDADD = \ + $(top_builddir)/src/cadet/libgnunetcadet.la \ + $(top_builddir)/src/util/libgnunetutil.la +gnunet_cadet_DEPENDENCIES = \ + libgnunetcadet.la + +gnunet_service_cadet_SOURCES = \ + gnunet-service-cadet_tunnel.c gnunet-service-cadet_tunnel.h \ + gnunet-service-cadet_connection.c gnunet-service-cadet_connection.h \ + gnunet-service-cadet_channel.c gnunet-service-cadet_channel.h \ + gnunet-service-cadet_local.c gnunet-service-cadet_local.h \ + gnunet-service-cadet_peer.c gnunet-service-cadet_peer.h \ + gnunet-service-cadet_dht.c gnunet-service-cadet_dht.h \ + gnunet-service-cadet_hello.c gnunet-service-cadet_hello.h \ + cadet_path.c cadet_path.h \ + cadet_common.c \ + gnunet-service-cadet.c +gnunet_service_cadet_CFLAGS = $(AM_CFLAGS) +gnunet_service_cadet_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/block/libgnunetblock.la +gnunet_service_cadet_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/block/libgnunetblock.la +if LINUX + gnunet_service_cadet_LDFLAGS = -lrt +endif + + +if HAVE_TESTING + noinst_LIBRARIES = libgnunetcadettest.a $(noinst_LIB_EXP) + noinst_PROGRAMS = gnunet-cadet-profiler +endif + +libgnunetcadettest_a_SOURCES = \ + cadet_test_lib.c cadet_test_lib.h +libgnunetcadettest_a_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testbed/libgnunettestbed.la \ + $(top_builddir)/src/cadet/libgnunetcadet.la +libgnunetcadettest_a_DEPENDENCIES = \ + libgnunetcadet.la + +if HAVE_TESTING +check_PROGRAMS = \ + test_cadet_single \ + test_cadet_local \ + test_cadet_forward \ + test_cadet_signal \ + test_cadet_keepalive \ + test_cadet_speed \ + test_cadet_speed_ack \ + test_cadet_speed_backwards \ + test_cadet_speed_reliable \ + test_cadet_speed_reliable_backwards +endif + +ld_cadet_test_lib = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/cadet/libgnunetcadettest.a \ + $(top_builddir)/src/cadet/libgnunetcadet.la \ + $(top_builddir)/src/testbed/libgnunettestbed.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la + +dep_cadet_test_lib = \ + libgnunetcadet.la \ + libgnunetcadettest.a \ + $(top_builddir)/src/statistics/libgnunetstatistics.la + + +gnunet_cadet_profiler_SOURCES = \ + gnunet-cadet-profiler.c +gnunet_cadet_profiler_LDADD = $(ld_cadet_test_lib) +gnunet_cadet_profiler_DEPENDENCIES = $(dep_cadet_test_lib) + + +test_cadet_single_SOURCES = \ + test_cadet_single.c +test_cadet_single_LDADD = $(ld_cadet_test_lib) +test_cadet_single_DEPENDENCIES = $(dep_cadet_test_lib) + +test_cadet_local_SOURCES = \ + test_cadet_local.c +test_cadet_local_LDADD = $(ld_cadet_test_lib) +test_cadet_local_DEPENDENCIES = $(dep_cadet_test_lib) + +test_cadet_forward_SOURCES = \ + test_cadet.c +test_cadet_forward_LDADD = $(ld_cadet_test_lib) +test_cadet_forward_DEPENDENCIES = $(dep_cadet_test_lib) + +test_cadet_signal_SOURCES = \ + test_cadet.c +test_cadet_signal_LDADD = $(ld_cadet_test_lib) +test_cadet_signal_DEPENDENCIES = $(dep_cadet_test_lib) + +test_cadet_keepalive_SOURCES = \ + test_cadet.c +test_cadet_keepalive_LDADD = $(ld_cadet_test_lib) +test_cadet_keepalive_DEPENDENCIES = $(dep_cadet_test_lib) + +test_cadet_speed_SOURCES = \ + test_cadet.c +test_cadet_speed_LDADD = $(ld_cadet_test_lib) +test_cadet_speed_DEPENDENCIES = $(dep_cadet_test_lib) + +test_cadet_speed_ack_SOURCES = \ + test_cadet.c +test_cadet_speed_ack_LDADD = $(ld_cadet_test_lib) +test_cadet_speed_ack_DEPENDENCIES = $(dep_cadet_test_lib) + +test_cadet_speed_backwards_SOURCES = \ + test_cadet.c +test_cadet_speed_backwards_LDADD = $(ld_cadet_test_lib) +test_cadet_speed_backwards_DEPENDENCIES = $(dep_cadet_test_lib) + +test_cadet_speed_reliable_SOURCES = \ + test_cadet.c +test_cadet_speed_reliable_LDADD = $(ld_cadet_test_lib) +test_cadet_speed_reliable_DEPENDENCIES = $(dep_cadet_test_lib) + +test_cadet_speed_reliable_backwards_SOURCES = \ + test_cadet.c +test_cadet_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib) +test_cadet_speed_reliable_backwards_DEPENDENCIES = $(dep_cadet_test_lib) + + +if ENABLE_TEST_RUN +AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; +TESTS = \ + $(check_PROGRAMS) +endif + +EXTRA_DIST = \ + cadet.h cadet_protocol.h \ + test_cadet.conf \ + test_cadet_drop.conf + diff --git a/src/cadet/beautify_log.sh b/src/cadet/beautify_log.sh new file mode 100755 index 000000000..b12f20380 --- /dev/null +++ b/src/cadet/beautify_log.sh @@ -0,0 +1,18 @@ +#!/bin/sh +grep "STARTING SERVICE " log > __tmp_peers +SED_EXPR="" +while read -r line; do + PEER=`echo $line | sed -e 's/.*\[\(....\)\].*/\1/'` + PID=`echo $line | sed -e 's/.*mesh-\([0-9]*\).*/\1/'` + echo "$PID => $PEER" + SED_EXPR="${SED_EXPR}s/mesh-\([a-z2]*\)-$PID/MESH \1 $PEER/;" + SED_EXPR="${SED_EXPR}s/mesh-$PID/MESH XXX $PEER/;" +done < __tmp_peers +rm __tmp_peers + +SED_EXPR="${SED_EXPR}s/mesh-api-/mesh-api- /g" +sed -e "$SED_EXPR" log > .log + +if [[ "`ps aux | grep "kwrite .lo[g]"`" = "" ]]; then + kwrite .log --geometry 960x1140-960 & +fi diff --git a/src/cadet/cadet.h b/src/cadet/cadet.h new file mode 100644 index 000000000..757f8c501 --- /dev/null +++ b/src/cadet/cadet.h @@ -0,0 +1,351 @@ +/* + This file is part of GNUnet. + (C) 2001 - 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. +*/ + +/** + * @author Bartlomiej Polot + * @file cadet/cadet.h + */ + +#ifndef CADET_H_ +#define CADET_H_ + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include + +#define CADET_DEBUG GNUNET_YES + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_peer_lib.h" +#include "gnunet_core_service.h" +#include "gnunet_protocols.h" +#include + +/******************************************************************************/ +/************************** CONSTANTS ******************************/ +/******************************************************************************/ + +#define GNUNET_CADET_LOCAL_CHANNEL_ID_CLI 0x80000000 +#define GNUNET_CADET_LOCAL_CHANNEL_ID_SERV 0xB0000000 + +#define HIGH_PID 0xFFFF0000 +#define LOW_PID 0x0000FFFF + +#define PID_OVERFLOW(pid, max) (pid > HIGH_PID && max < LOW_PID) + +/******************************************************************************/ +/************************** MESSAGES ******************************/ +/******************************************************************************/ + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message for a client to register to the service + */ +struct GNUNET_CADET_ClientConnect +{ + /** + * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT + * + * Size: sizeof(struct GNUNET_CADET_ClientConnect) + + * sizeof(CADET_ApplicationType) * applications + + * sizeof(uint16_t) * types + */ + struct GNUNET_MessageHeader header; + /* uint32_t list_ports[] */ +}; + + +/** + * Type for channel numbering. + * - Local channel numbers given by the service (incoming) are >= 0xB0000000 + * - Local channel numbers given by the client (created) are >= 0x80000000 + * - Global channel numbers are < 0x80000000 + */ +typedef uint32_t CADET_ChannelNumber; + + +/** + * Message for a client to create and destroy channels. + */ +struct GNUNET_CADET_ChannelMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_TUNNEL_[CREATE|DESTROY] + * + * Size: sizeof(struct GNUNET_CADET_ChannelMessage) + */ + struct GNUNET_MessageHeader header; + + /** + * ID of a channel controlled by this client. + */ + CADET_ChannelNumber channel_id GNUNET_PACKED; + + /** + * Channel's peer + */ + struct GNUNET_PeerIdentity peer; + + /** + * Port of the channel. + */ + uint32_t port GNUNET_PACKED; + + /** + * Options. + */ + uint32_t opt GNUNET_PACKED; +}; + + +/** + * Message for cadet data traffic. + */ +struct GNUNET_CADET_LocalData +{ + /** + * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA + */ + struct GNUNET_MessageHeader header; + + /** + * ID of the channel + */ + uint32_t id GNUNET_PACKED; + + /** + * Payload follows + */ +}; + + +/** + * Message to allow the client send more data to the service + * (always service -> client). + */ +struct GNUNET_CADET_LocalAck +{ + /** + * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK + */ + struct GNUNET_MessageHeader header; + + /** + * ID of the channel allowed to send more data. + */ + CADET_ChannelNumber channel_id GNUNET_PACKED; + +}; + + +/** + * Message to inform the client about channels in the service. + */ +struct GNUNET_CADET_LocalInfo +{ + /** + * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO[_TUNNEL,_PEER] + */ + struct GNUNET_MessageHeader header; + + /** + * ID of the channel allowed to send more data. + */ + CADET_ChannelNumber channel_id GNUNET_PACKED; + + /** + * ID of the owner of the channel (can be local peer). + */ +// struct GNUNET_PeerIdentity owner; + + /** + * ID of the destination of the channel (can be local peer). + */ + struct GNUNET_PeerIdentity peer; +}; + + +/** + * Message to inform the client about one of the peers in the service. + */ +struct GNUNET_CADET_LocalInfoPeer +{ + /** + * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER[S] + */ + struct GNUNET_MessageHeader header; + + /** + * Number of paths. + */ + uint16_t paths GNUNET_PACKED; + + /** + * Do we have a tunnel toward this peer? + */ + int16_t tunnel GNUNET_PACKED; + + /** + * ID of the destination of the tunnel (can be local peer). + */ + struct GNUNET_PeerIdentity destination; + + /* If type == PEER (no 'S'): GNUNET_PeerIdentity paths[] + * (each path ends in destination) */ +}; + +/** + * Message to inform the client about one of the tunnels in the service. + */ +struct GNUNET_CADET_LocalInfoTunnel +{ + /** + * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL[S] + */ + struct GNUNET_MessageHeader header; + + /** + * Number of channels. + */ + uint32_t channels GNUNET_PACKED; + + /** + * ID of the destination of the tunnel (can be local peer). + */ + struct GNUNET_PeerIdentity destination; + + /** + * Number of connections. + */ + uint32_t connections GNUNET_PACKED; + + /** + * Encryption state. + */ + uint16_t estate GNUNET_PACKED; + + /** + * Connection state. + */ + uint16_t cstate GNUNET_PACKED; + + /* If TUNNEL (no 'S'): GNUNET_PeerIdentity connection_ids[connections] */ + /* If TUNNEL (no 'S'): uint32_t channel_ids[channels] */ +}; + + +GNUNET_NETWORK_STRUCT_END + + + +/** + * @brief Translate a fwd variable into a string representation, for logging. + * + * @param fwd Is FWD? (#GNUNET_YES or #GNUNET_NO) + * + * @return String representing FWD or BCK. + */ +char * +GM_f2s (int fwd); + + +/** + * Check if one pid is bigger than other, accounting for overflow. + * + * @param bigger Argument that should be bigger. + * @param smaller Argument that should be smaller. + * + * @return True if bigger (arg1) has a higher value than smaller (arg 2). + */ +int +GM_is_pid_bigger (uint32_t bigger, uint32_t smaller); + + +/** + * Get the higher ACK value out of two values, taking in account overflow. + * + * @param a First ACK value. + * @param b Second ACK value. + * + * @return Highest ACK value from the two. + */ +uint32_t +GM_max_pid (uint32_t a, uint32_t b); + + +/** + * Get the lower ACK value out of two values, taking in account overflow. + * + * @param a First ACK value. + * @param b Second ACK value. + * + * @return Lowest ACK value from the two. + */ +uint32_t +GM_min_pid (uint32_t a, uint32_t b); + + +/** + * Convert a 256 bit CadetHash into a 512 HashCode to use in GNUNET_h2s, + * multihashmap, and other HashCode-based functions. + * + * @param id A 256 bit hash to expand. + * + * @return A HashCode containing the original 256 bit hash right-padded with 0. + */ +const struct GNUNET_HashCode * +GM_h2hc (const struct GNUNET_CADET_Hash *id); + +/** + * Get a string from a Cadet Hash (256 bits). + * WARNING: Not reentrant (based on GNUNET_h2s). + */ +const char * +GM_h2s (const struct GNUNET_CADET_Hash *id); + +/** + * Convert a message type into a string to help debug + * Generated with: + * FIND: "#define ([^ ]+)[ ]*([0-9]+)" + * REPLACE: " case \2: return "\1"; break;" + * + * @param m Message type. + * + * @return Human readable string description. + */ +const char * +GM_m2s (uint16_t m); + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/cadet/cadet_api.c b/src/cadet/cadet_api.c new file mode 100644 index 000000000..aa5c67329 --- /dev/null +++ b/src/cadet/cadet_api.c @@ -0,0 +1,2141 @@ +/* + 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 cadet/cadet_api.c + * @brief cadet api: client implementation of new cadet service + * @author Bartlomiej Polot + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_cadet_service.h" +#include "cadet.h" +#include "cadet_protocol.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "cadet-api",__VA_ARGS__) + +/******************************************************************************/ +/************************ DATA STRUCTURES ****************************/ +/******************************************************************************/ + +/** + * Transmission queue to the service + */ +struct GNUNET_CADET_TransmitHandle +{ + + /** + * Double Linked list + */ + struct GNUNET_CADET_TransmitHandle *next; + + /** + * Double Linked list + */ + struct GNUNET_CADET_TransmitHandle *prev; + + /** + * Channel this message is sent on / for (may be NULL for control messages). + */ + struct GNUNET_CADET_Channel *channel; + + /** + * Callback to obtain the message to transmit, or NULL if we + * got the message in 'data'. Notice that messages built + * by 'notify' need to be encapsulated with information about + * the 'target'. + */ + GNUNET_CONNECTION_TransmitReadyNotify notify; + + /** + * Closure for 'notify' + */ + void *notify_cls; + + /** + * How long is this message valid. Once the timeout has been + * reached, the message must no longer be sent. If this + * is a message with a 'notify' callback set, the 'notify' + * function should be called with 'buf' NULL and size 0. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Task triggering a timeout, can be NO_TASK if the timeout is FOREVER. + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** + * Size of 'data' -- or the desired size of 'notify' if 'data' is NULL. + */ + size_t size; +}; + +union CadetInfoCB { + + /** + * Channel callback. + */ + GNUNET_CADET_ChannelCB channel_cb; + + /** + * Monitor callback + */ + GNUNET_CADET_PeersCB peers_cb; + + /** + * Monitor callback + */ + GNUNET_CADET_PeerCB peer_cb; + + /** + * Monitor callback + */ + GNUNET_CADET_TunnelsCB tunnels_cb; + + /** + * Tunnel callback. + */ + GNUNET_CADET_TunnelCB tunnel_cb; +}; + + +/** + * Opaque handle to the service. + */ +struct GNUNET_CADET_Handle +{ + + /** + * Handle to the server connection, to send messages later + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Set of handlers used for processing incoming messages in the channels + */ + const struct GNUNET_CADET_MessageHandler *message_handlers; + + /** + * Number of handlers in the handlers array. + */ + unsigned int n_handlers; + + /** + * Ports open. + */ + const uint32_t *ports; + + /** + * Number of ports. + */ + unsigned int n_ports; + + /** + * Double linked list of the channels this client is connected to, head. + */ + struct GNUNET_CADET_Channel *channels_head; + + /** + * Double linked list of the channels this client is connected to, tail. + */ + struct GNUNET_CADET_Channel *channels_tail; + + /** + * Callback for inbound channel creation + */ + GNUNET_CADET_InboundChannelNotificationHandler *new_channel; + + /** + * Callback for inbound channel disconnection + */ + GNUNET_CADET_ChannelEndHandler *cleaner; + + /** + * Handle to cancel pending transmissions in case of disconnection + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * Closure for all the handlers given by the client + */ + void *cls; + + /** + * Messages to send to the service, head. + */ + struct GNUNET_CADET_TransmitHandle *th_head; + + /** + * Messages to send to the service, tail. + */ + struct GNUNET_CADET_TransmitHandle *th_tail; + + /** + * chid of the next channel to create (to avoid reusing IDs often) + */ + CADET_ChannelNumber next_chid; + + /** + * Have we started the task to receive messages from the service + * yet? We do this after we send the 'CADET_LOCAL_CONNECT' message. + */ + int in_receive; + + /** + * Configuration given by the client, in case of reconnection + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Time to the next reconnect in case one reconnect fails + */ + struct GNUNET_TIME_Relative reconnect_time; + + /** + * Task for trying to reconnect. + */ + GNUNET_SCHEDULER_TaskIdentifier reconnect_task; + + /** + * Callback for an info task (only one active at a time). + */ + union CadetInfoCB info_cb; + + /** + * Info callback closure for @c info_cb. + */ + void *info_cls; +}; + + +/** + * Description of a peer + */ +struct GNUNET_CADET_Peer +{ + /** + * ID of the peer in short form + */ + GNUNET_PEER_Id id; + + /** + * Channel this peer belongs to + */ + struct GNUNET_CADET_Channel *t; +}; + + +/** + * Opaque handle to a channel. + */ +struct GNUNET_CADET_Channel +{ + + /** + * DLL next + */ + struct GNUNET_CADET_Channel *next; + + /** + * DLL prev + */ + struct GNUNET_CADET_Channel *prev; + + /** + * Handle to the cadet this channel belongs to + */ + struct GNUNET_CADET_Handle *cadet; + + /** + * Local ID of the channel + */ + CADET_ChannelNumber chid; + + /** + * Port number. + */ + uint32_t port; + + /** + * Other end of the channel. + */ + GNUNET_PEER_Id peer; + + /** + * Any data the caller wants to put in here + */ + void *ctx; + + /** + * Size of packet queued in this channel + */ + unsigned int packet_size; + + /** + * Channel options: reliability, etc. + */ + enum GNUNET_CADET_ChannelOption options; + + /** + * Are we allowed to send to the service? + */ + int allow_send; + +}; + + +/** + * Implementation state for cadet's message queue. + */ +struct CadetMQState +{ + /** + * The current transmit handle, or NULL + * if no transmit is active. + */ + struct GNUNET_CADET_TransmitHandle *th; + + /** + * Channel to send the data over. + */ + struct GNUNET_CADET_Channel *channel; +}; + + +/******************************************************************************/ +/*********************** DECLARATIONS *************************/ +/******************************************************************************/ + +/** + * Function called to send a message to the service. + * "buf" will be NULL and "size" zero if the socket was closed for writing in + * the meantime. + * + * @param cls closure, the cadet handle + * @param size number of bytes available in buf + * @param buf where the callee should write the connect message + * @return number of bytes written to buf + */ +static size_t +send_callback (void *cls, size_t size, void *buf); + + +/******************************************************************************/ +/*********************** AUXILIARY FUNCTIONS *************************/ +/******************************************************************************/ + +/** + * Check if transmission is a payload packet. + * + * @param th Transmission handle. + * + * @return GNUNET_YES if it is a payload packet, + * GNUNET_NO if it is a cadet management packet. + */ +static int +th_is_payload (struct GNUNET_CADET_TransmitHandle *th) +{ + return (th->notify != NULL) ? GNUNET_YES : GNUNET_NO; +} + + +/** + * Check whether there is any message ready in the queue and find the size. + * + * @param h Cadet handle. + * + * @return The size of the first ready message in the queue, + * 0 if there is none. + */ +static size_t +message_ready_size (struct GNUNET_CADET_Handle *h) +{ + struct GNUNET_CADET_TransmitHandle *th; + struct GNUNET_CADET_Channel *ch; + + for (th = h->th_head; NULL != th; th = th->next) + { + ch = th->channel; + if (GNUNET_NO == th_is_payload (th)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "# message internal\n"); + return th->size; + } + if (GNUNET_YES == ch->allow_send) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "# message payload ok\n"); + return th->size; + } + } + return 0; +} + + +/** + * Get the channel handler for the channel specified by id from the given handle + * @param h Cadet handle + * @param chid ID of the wanted channel + * @return handle to the required channel or NULL if not found + */ +static struct GNUNET_CADET_Channel * +retrieve_channel (struct GNUNET_CADET_Handle *h, CADET_ChannelNumber chid) +{ + struct GNUNET_CADET_Channel *ch; + + ch = h->channels_head; + while (ch != NULL) + { + if (ch->chid == chid) + return ch; + ch = ch->next; + } + return NULL; +} + + +/** + * Create a new channel and insert it in the channel list of the cadet handle + * + * @param h Cadet handle + * @param chid Desired chid of the channel, 0 to assign one automatically. + * + * @return Handle to the created channel. + */ +static struct GNUNET_CADET_Channel * +create_channel (struct GNUNET_CADET_Handle *h, CADET_ChannelNumber chid) +{ + struct GNUNET_CADET_Channel *ch; + + ch = GNUNET_new (struct GNUNET_CADET_Channel); + GNUNET_CONTAINER_DLL_insert (h->channels_head, h->channels_tail, ch); + ch->cadet = h; + if (0 == chid) + { + ch->chid = h->next_chid; + while (NULL != retrieve_channel (h, h->next_chid)) + { + h->next_chid++; + h->next_chid &= ~GNUNET_CADET_LOCAL_CHANNEL_ID_SERV; + h->next_chid |= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI; + } + } + else + { + ch->chid = chid; + } + ch->allow_send = GNUNET_NO; + return ch; +} + + +/** + * Destroy the specified channel. + * - Destroys all peers, calling the disconnect callback on each if needed + * - Cancels all outgoing traffic for that channel, calling respective notifys + * - Calls cleaner if channel was inbound + * - Frees all memory used + * + * @param ch Pointer to the channel. + * @param call_cleaner Whether to call the cleaner handler. + * + * @return Handle to the required channel or NULL if not found. + */ +static void +destroy_channel (struct GNUNET_CADET_Channel *ch, int call_cleaner) +{ + struct GNUNET_CADET_Handle *h; + struct GNUNET_CADET_TransmitHandle *th; + struct GNUNET_CADET_TransmitHandle *next; + + LOG (GNUNET_ERROR_TYPE_DEBUG, " destroy_channel %X\n", ch->chid); + + if (NULL == ch) + { + GNUNET_break (0); + return; + } + h = ch->cadet; + + GNUNET_CONTAINER_DLL_remove (h->channels_head, h->channels_tail, ch); + + /* signal channel destruction */ + if ( (NULL != h->cleaner) && (0 != ch->peer) && (GNUNET_YES == call_cleaner) ) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " calling cleaner\n"); + h->cleaner (h->cls, ch, ch->ctx); + } + + /* check that clients did not leave messages behind in the queue */ + for (th = h->th_head; NULL != th; th = next) + { + next = th->next; + if (th->channel != ch) + continue; + /* Clients should have aborted their requests already. + * Management traffic should be ok, as clients can't cancel that. + * If the service crashed and we are reconnecting, it's ok. + */ + GNUNET_break (GNUNET_NO == th_is_payload (th) + || GNUNET_NO == h->in_receive); + GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th); + + /* clean up request */ + if (GNUNET_SCHEDULER_NO_TASK != th->timeout_task) + GNUNET_SCHEDULER_cancel (th->timeout_task); + GNUNET_free (th); + } + + /* if there are no more pending requests with cadet service, cancel active request */ + /* Note: this should be unnecessary... */ + if ((0 == message_ready_size (h)) && (NULL != h->th)) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); + h->th = NULL; + } + + if (0 != ch->peer) + GNUNET_PEER_change_rc (ch->peer, -1); + GNUNET_free (ch); + return; +} + + +/** + * Notify client that the transmission has timed out + * + * @param cls closure + * @param tc task context + */ +static void +timeout_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_CADET_TransmitHandle *th = cls; + struct GNUNET_CADET_Handle *cadet; + + cadet = th->channel->cadet; + GNUNET_CONTAINER_DLL_remove (cadet->th_head, cadet->th_tail, th); + th->channel->packet_size = 0; + if (GNUNET_YES == th_is_payload (th)) + th->notify (th->notify_cls, 0, NULL); + GNUNET_free (th); + if ((0 == message_ready_size (cadet)) && (NULL != cadet->th)) + { + /* nothing ready to transmit, no point in asking for transmission */ + GNUNET_CLIENT_notify_transmit_ready_cancel (cadet->th); + cadet->th = NULL; + } +} + + +/** + * Add a transmit handle to the transmission queue and set the + * timeout if needed. + * + * @param h cadet handle with the queue head and tail + * @param th handle to the packet to be transmitted + */ +static void +add_to_queue (struct GNUNET_CADET_Handle *h, + struct GNUNET_CADET_TransmitHandle *th) +{ + GNUNET_CONTAINER_DLL_insert_tail (h->th_head, h->th_tail, th); + if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us == th->timeout.abs_value_us) + return; + th->timeout_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (th->timeout), &timeout_transmission, th); +} + + +/** + * Auxiliary function to send an already constructed packet to the service. + * Takes care of creating a new queue element, copying the message and + * calling the tmt_rdy function if necessary. + * + * @param h cadet handle + * @param msg message to transmit + * @param channel channel this send is related to (NULL if N/A) + */ +static void +send_packet (struct GNUNET_CADET_Handle *h, + const struct GNUNET_MessageHeader *msg, + struct GNUNET_CADET_Channel *channel); + + +/** + * Send an ack on the channel to confirm the processing of a message. + * + * @param ch Channel on which to send the ACK. + */ +static void +send_ack (struct GNUNET_CADET_Channel *ch) +{ + struct GNUNET_CADET_LocalAck msg; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending ACK on channel %X\n", ch->chid); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK); + msg.header.size = htons (sizeof (msg)); + msg.channel_id = htonl (ch->chid); + + send_packet (ch->cadet, &msg.header, ch); + return; +} + + + +/** + * Reconnect callback: tries to reconnect again after a failer previous + * reconnecttion + * @param cls closure (cadet handle) + * @param tc task context + */ +static void +reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Send a connect packet to the service with the applications and types + * requested by the user. + * + * @param h The cadet handle. + * + */ +static void +send_connect (struct GNUNET_CADET_Handle *h) +{ + size_t size; + + size = sizeof (struct GNUNET_CADET_ClientConnect); + size += h->n_ports * sizeof (uint32_t); + { + char buf[size] GNUNET_ALIGN; + struct GNUNET_CADET_ClientConnect *msg; + uint32_t *ports; + uint16_t i; + + /* build connection packet */ + msg = (struct GNUNET_CADET_ClientConnect *) buf; + msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT); + msg->header.size = htons (size); + ports = (uint32_t *) &msg[1]; + for (i = 0; i < h->n_ports; i++) + { + ports[i] = htonl (h->ports[i]); + LOG (GNUNET_ERROR_TYPE_DEBUG, " port %u\n", + h->ports[i]); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Sending %lu bytes long message with %u ports\n", + ntohs (msg->header.size), h->n_ports); + send_packet (h, &msg->header, NULL); + } +} + + +/** + * Reconnect to the service, retransmit all infomation to try to restore the + * original state. + * + * @param h handle to the cadet + * + * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...) + */ +static int +do_reconnect (struct GNUNET_CADET_Handle *h) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, "******* RECONNECT *******\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, "******** on %p *******\n", h); + LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n"); + + /* disconnect */ + if (NULL != h->th) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); + h->th = NULL; + } + if (NULL != h->client) + { + GNUNET_CLIENT_disconnect (h->client); + } + + /* connect again */ + h->client = GNUNET_CLIENT_connect ("cadet", h->cfg); + if (h->client == NULL) + { + h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time, + &reconnect_cbk, h); + h->reconnect_time = + GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS, + GNUNET_TIME_relative_multiply + (h->reconnect_time, 2)); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Next retry in %s\n", + GNUNET_STRINGS_relative_time_to_string (h->reconnect_time, + GNUNET_NO)); + GNUNET_break (0); + return GNUNET_NO; + } + else + { + h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS; + } + send_connect (h); + return GNUNET_YES; +} + +/** + * Reconnect callback: tries to reconnect again after a failer previous + * reconnecttion + * @param cls closure (cadet handle) + * @param tc task context + */ +static void +reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_CADET_Handle *h = cls; + + h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + do_reconnect (h); +} + + +/** + * Reconnect to the service, retransmit all infomation to try to restore the + * original state. + * + * @param h handle to the cadet + * + * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...) + */ +static void +reconnect (struct GNUNET_CADET_Handle *h) +{ + struct GNUNET_CADET_Channel *ch; + struct GNUNET_CADET_Channel *next; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Requested RECONNECT, destroying all channels\n"); + h->in_receive = GNUNET_NO; + for (ch = h->channels_head; NULL != ch; ch = next) + { + next = ch->next; + destroy_channel (ch, GNUNET_YES); + } + if (GNUNET_SCHEDULER_NO_TASK == h->reconnect_task) + h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time, + &reconnect_cbk, h); +} + + +/******************************************************************************/ +/*********************** RECEIVE HANDLERS ****************************/ +/******************************************************************************/ + +/** + * Process the new channel notification and add it to the channels in the handle + * + * @param h The cadet handle + * @param msg A message with the details of the new incoming channel + */ +static void +process_channel_created (struct GNUNET_CADET_Handle *h, + const struct GNUNET_CADET_ChannelMessage *msg) +{ + struct GNUNET_CADET_Channel *ch; + CADET_ChannelNumber chid; + uint32_t port; + + chid = ntohl (msg->channel_id); + port = ntohl (msg->port); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating incoming channel %X:%u\n", chid, port); + if (chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV) + { + GNUNET_break (0); + return; + } + if (NULL != h->new_channel) + { + void *ctx; + + ch = create_channel (h, chid); + ch->allow_send = GNUNET_NO; + ch->peer = GNUNET_PEER_intern (&msg->peer); + ch->cadet = h; + ch->chid = chid; + ch->port = port; + ch->options = ntohl (msg->opt); + + LOG (GNUNET_ERROR_TYPE_DEBUG, " created channel %p\n", ch); + ctx = h->new_channel (h->cls, ch, &msg->peer, ch->port, ch->options); + if (NULL != ctx) + ch->ctx = ctx; + LOG (GNUNET_ERROR_TYPE_DEBUG, "User notified\n"); + } + else + { + struct GNUNET_CADET_ChannelMessage d_msg; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "No handler for incoming channels\n"); + + d_msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY); + d_msg.header.size = htons (sizeof (struct GNUNET_CADET_ChannelMessage)); + d_msg.channel_id = msg->channel_id; + memset (&d_msg.peer, 0, sizeof (struct GNUNET_PeerIdentity)); + d_msg.port = 0; + d_msg.opt = 0; + + send_packet (h, &d_msg.header, NULL); + } + return; +} + + +/** + * Process the channel destroy notification and free associated resources + * + * @param h The cadet handle + * @param msg A message with the details of the channel being destroyed + */ +static void +process_channel_destroy (struct GNUNET_CADET_Handle *h, + const struct GNUNET_CADET_ChannelMessage *msg) +{ + struct GNUNET_CADET_Channel *ch; + CADET_ChannelNumber chid; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel Destroy received from service\n"); + chid = ntohl (msg->channel_id); + ch = retrieve_channel (h, chid); + + if (NULL == ch) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "channel %X unknown\n", chid); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " destroying channel %X\n", ch->chid); + destroy_channel (ch, GNUNET_YES); +} + + +/** + * Process the incoming data packets, call appropriate handlers. + * + * @param h The cadet handle + * @param message A message encapsulating the data + */ +static void +process_incoming_data (struct GNUNET_CADET_Handle *h, + const struct GNUNET_MessageHeader *message) +{ + const struct GNUNET_MessageHeader *payload; + const struct GNUNET_CADET_MessageHandler *handler; + struct GNUNET_CADET_LocalData *dmsg; + struct GNUNET_CADET_Channel *ch; + size_t size; + unsigned int i; + uint16_t type; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a data message!\n"); + dmsg = (struct GNUNET_CADET_LocalData *) message; + ch = retrieve_channel (h, ntohl (dmsg->id)); + if (NULL == ch) + { + GNUNET_break (0); + return; + } + + payload = (struct GNUNET_MessageHeader *) &dmsg[1]; + LOG (GNUNET_ERROR_TYPE_DEBUG, " %s data on channel %s [%X]\n", + GM_f2s (ch->chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV), + GNUNET_i2s (GNUNET_PEER_resolve2 (ch->peer)), ntohl (dmsg->id)); + + size = ntohs (message->size); + LOG (GNUNET_ERROR_TYPE_DEBUG, " %u bytes\n", size); + + if (NULL == ch) + { + /* Channel was ignored/destroyed, probably service didn't get it yet */ + LOG (GNUNET_ERROR_TYPE_DEBUG, " ignored!\n"); + return; + } + type = ntohs (payload->type); + size = ntohs (payload->size); + LOG (GNUNET_ERROR_TYPE_DEBUG, " payload type %s\n", GM_m2s (type)); + for (i = 0; i < h->n_handlers; i++) + { + handler = &h->message_handlers[i]; + LOG (GNUNET_ERROR_TYPE_DEBUG, " checking handler for type %u\n", + handler->type); + if (handler->type == type) + { + if (GNUNET_OK != + handler->callback (h->cls, ch, &ch->ctx, payload)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "callback caused disconnection\n"); + GNUNET_CADET_channel_destroy (ch); + return; + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "callback completed successfully\n"); + return; + } + } + } +} + + +/** + * Process a local ACK message, enabling the client to send + * more data to the service. + * + * @param h Cadet handle. + * @param message Message itself. + */ +static void +process_ack (struct GNUNET_CADET_Handle *h, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_CADET_LocalAck *msg; + struct GNUNET_CADET_Channel *ch; + CADET_ChannelNumber chid; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Got an ACK!\n"); + msg = (struct GNUNET_CADET_LocalAck *) message; + chid = ntohl (msg->channel_id); + ch = retrieve_channel (h, chid); + if (NULL == ch) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "ACK on unknown channel %X\n", chid); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X!\n", ch->chid); + ch->allow_send = GNUNET_YES; + if (NULL == h->th && 0 < ch->packet_size) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " tmt rdy was NULL, requesting!\n"); + h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, ch->packet_size, + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, &send_callback, h); + } +} + + +/* + * Process a local reply about info on all channels, pass info to the user. + * + * @param h Cadet handle. + * @param message Message itself. + */ +// static void +// process_get_channels (struct GNUNET_CADET_Handle *h, +// const struct GNUNET_MessageHeader *message) +// { +// struct GNUNET_CADET_LocalInfo *msg; +// +// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Get Channels messasge received\n"); +// +// if (NULL == h->channels_cb) +// { +// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " ignored\n"); +// return; +// } +// +// msg = (struct GNUNET_CADET_LocalInfo *) message; +// if (ntohs (message->size) != +// (sizeof (struct GNUNET_CADET_LocalInfo) + +// sizeof (struct GNUNET_PeerIdentity))) +// { +// GNUNET_break_op (0); +// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +// "Get channels message: size %hu - expected %u\n", +// ntohs (message->size), +// sizeof (struct GNUNET_CADET_LocalInfo)); +// return; +// } +// h->channels_cb (h->channels_cls, +// ntohl (msg->channel_id), +// &msg->owner, +// &msg->destination); +// } + + + +/* + * Process a local monitor_channel reply, pass info to the user. + * + * @param h Cadet handle. + * @param message Message itself. + */ +// static void +// process_show_channel (struct GNUNET_CADET_Handle *h, +// const struct GNUNET_MessageHeader *message) +// { +// struct GNUNET_CADET_LocalInfo *msg; +// size_t esize; +// +// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Show Channel messasge received\n"); +// +// if (NULL == h->channel_cb) +// { +// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " ignored\n"); +// return; +// } +// +// /* Verify message sanity */ +// msg = (struct GNUNET_CADET_LocalInfo *) message; +// esize = sizeof (struct GNUNET_CADET_LocalInfo); +// if (ntohs (message->size) != esize) +// { +// GNUNET_break_op (0); +// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +// "Show channel message: size %hu - expected %u\n", +// ntohs (message->size), +// esize); +// +// h->channel_cb (h->channel_cls, NULL, NULL); +// h->channel_cb = NULL; +// h->channel_cls = NULL; +// +// return; +// } +// +// h->channel_cb (h->channel_cls, +// &msg->destination, +// &msg->owner); +// } + + + +/** + * Process a local reply about info on all tunnels, pass info to the user. + * + * @param h Cadet handle. + * @param message Message itself. + */ +static void +process_get_peers (struct GNUNET_CADET_Handle *h, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_CADET_LocalInfoPeer *msg; + uint16_t size; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Get Peer messasge received\n"); + + if (NULL == h->info_cb.peers_cb) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ignored\n"); + return; + } + + size = ntohs (message->size); + if (sizeof (struct GNUNET_CADET_LocalInfoPeer) > size) + { + h->info_cb.peers_cb (h->info_cls, NULL, -1, 0, 0); + h->info_cb.peers_cb = NULL; + h->info_cls = NULL; + return; + } + + msg = (struct GNUNET_CADET_LocalInfoPeer *) message; + h->info_cb.peers_cb (h->info_cls, &msg->destination, + (int) ntohs (msg->tunnel), + (unsigned int ) ntohs (msg->paths), + 0); +} + + +/** + * Process a local peer info reply, pass info to the user. + * + * @param h Cadet handle. + * @param message Message itself. + */ +static void +process_get_peer (struct GNUNET_CADET_Handle *h, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_CADET_LocalInfoTunnel *msg; + size_t esize; + size_t msize; + unsigned int ch_n; + unsigned int c_n; + struct GNUNET_CADET_Hash *conns; + CADET_ChannelNumber *chns; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Get Tunnel messasge received\n"); + if (NULL == h->info_cb.tunnel_cb) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ignored\n"); + return; + } + + /* Verify message sanity */ + msg = (struct GNUNET_CADET_LocalInfoTunnel *) message; + msize = ntohs (message->size); + esize = sizeof (struct GNUNET_CADET_LocalInfoTunnel); + if (esize > msize) + { + GNUNET_break_op (0); + h->info_cb.tunnel_cb (h->info_cls, NULL, 0, 0, NULL, NULL, 0, 0); + goto clean_cls; + } + ch_n = ntohl (msg->channels); + c_n = ntohl (msg->connections); + esize += ch_n * sizeof (CADET_ChannelNumber); + esize += c_n * sizeof (struct GNUNET_CADET_Hash); + if (msize != esize) + { + GNUNET_break_op (0); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "m:%u, e: %u (%u ch, %u conn)\n", + msize, esize, ch_n, c_n); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%u (%u ch, %u conn)\n", + sizeof (struct GNUNET_CADET_LocalInfoTunnel), + sizeof (CADET_ChannelNumber), sizeof (struct GNUNET_HashCode)); + h->info_cb.tunnel_cb (h->info_cls, NULL, 0, 0, NULL, NULL, 0, 0); + goto clean_cls; + } + + /* Call Callback with tunnel info. */ + conns = (struct GNUNET_CADET_Hash *) &msg[1]; + chns = (CADET_ChannelNumber *) &conns[c_n]; + h->info_cb.tunnel_cb (h->info_cls, &msg->destination, + ch_n, c_n, chns, conns, + ntohs (msg->estate), ntohs (msg->cstate)); + + clean_cls: + h->info_cb.tunnel_cb = NULL; + h->info_cls = NULL; +} + + +/** + * Process a local reply about info on all tunnels, pass info to the user. + * + * @param h Cadet handle. + * @param message Message itself. + */ +static void +process_get_tunnels (struct GNUNET_CADET_Handle *h, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_CADET_LocalInfoTunnel *msg; + uint16_t size; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Get Tunnels messasge received\n"); + + if (NULL == h->info_cb.tunnels_cb) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ignored\n"); + return; + } + + size = ntohs (message->size); + if (sizeof (struct GNUNET_CADET_LocalInfoTunnel) > size) + { + h->info_cb.tunnels_cb (h->info_cls, NULL, 0, 0, 0, 0); + h->info_cb.tunnels_cb = NULL; + h->info_cls = NULL; + return; + } + + msg = (struct GNUNET_CADET_LocalInfoTunnel *) message; + h->info_cb.tunnels_cb (h->info_cls, &msg->destination, + ntohl (msg->channels), ntohl (msg->connections), + ntohs (msg->estate), ntohs (msg->cstate)); + +} + + +/** + * Process a local tunnel info reply, pass info to the user. + * + * @param h Cadet handle. + * @param message Message itself. + */ +static void +process_get_tunnel (struct GNUNET_CADET_Handle *h, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_CADET_LocalInfoTunnel *msg; + size_t esize; + size_t msize; + unsigned int ch_n; + unsigned int c_n; + struct GNUNET_CADET_Hash *conns; + CADET_ChannelNumber *chns; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Get Tunnel messasge received\n"); + if (NULL == h->info_cb.tunnel_cb) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ignored\n"); + return; + } + + /* Verify message sanity */ + msg = (struct GNUNET_CADET_LocalInfoTunnel *) message; + msize = ntohs (message->size); + esize = sizeof (struct GNUNET_CADET_LocalInfoTunnel); + if (esize > msize) + { + GNUNET_break_op (0); + h->info_cb.tunnel_cb (h->info_cls, NULL, 0, 0, NULL, NULL, 0, 0); + goto clean_cls; + } + ch_n = ntohl (msg->channels); + c_n = ntohl (msg->connections); + esize += ch_n * sizeof (CADET_ChannelNumber); + esize += c_n * sizeof (struct GNUNET_CADET_Hash); + if (msize != esize) + { + GNUNET_break_op (0); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "m:%u, e: %u (%u ch, %u conn)\n", + msize, esize, ch_n, c_n); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%u (%u ch, %u conn)\n", + sizeof (struct GNUNET_CADET_LocalInfoTunnel), + sizeof (CADET_ChannelNumber), sizeof (struct GNUNET_HashCode)); + h->info_cb.tunnel_cb (h->info_cls, NULL, 0, 0, NULL, NULL, 0, 0); + goto clean_cls; + } + + /* Call Callback with tunnel info. */ + conns = (struct GNUNET_CADET_Hash *) &msg[1]; + chns = (CADET_ChannelNumber *) &conns[c_n]; + h->info_cb.tunnel_cb (h->info_cls, &msg->destination, + ch_n, c_n, chns, conns, + ntohs (msg->estate), ntohs (msg->cstate)); + +clean_cls: + h->info_cb.tunnel_cb = NULL; + h->info_cls = NULL; +} + + +/** + * Function to process all messages received from the service + * + * @param cls closure + * @param msg message received, NULL on timeout or fatal error + */ +static void +msg_received (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_CADET_Handle *h = cls; + uint16_t type; + + if (msg == NULL) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Cadet service disconnected, reconnecting\n", h); + reconnect (h); + return; + } + type = ntohs (msg->type); + LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Received a message: %s\n", + GM_m2s (type)); + switch (type) + { + /* Notify of a new incoming channel */ + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE: + process_channel_created (h, (struct GNUNET_CADET_ChannelMessage *) msg); + break; + /* Notify of a channel disconnection */ + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: /* TODO separate(gid problem)*/ + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK: + process_channel_destroy (h, (struct GNUNET_CADET_ChannelMessage *) msg); + break; + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA: + process_incoming_data (h, msg); + break; + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK: + process_ack (h, msg); + break; +// case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNELS: +// process_get_channels (h, msg); +// break; +// case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL: +// process_show_channel (h, msg); +// break; + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS: + process_get_peers (h, msg); + break; + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER: + process_get_peer (h, msg); + break; + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS: + process_get_tunnels (h, msg); + break; + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL: + process_get_tunnel (h, msg); + break; +// case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL: +// process_show_channel (h, msg); +// break; + default: + /* We shouldn't get any other packages, log and ignore */ + LOG (GNUNET_ERROR_TYPE_WARNING, + "unsolicited message form service (type %s)\n", + GM_m2s (ntohs (msg->type))); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "message processed\n"); + if (GNUNET_YES == h->in_receive) + { + GNUNET_CLIENT_receive (h->client, &msg_received, h, + GNUNET_TIME_UNIT_FOREVER_REL); + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "in receive off, not calling CLIENT_receive\n"); + } +} + + +/******************************************************************************/ +/************************ SEND FUNCTIONS ****************************/ +/******************************************************************************/ + +/** + * Function called to send a message to the service. + * "buf" will be NULL and "size" zero if the socket was closed for writing in + * the meantime. + * + * @param cls closure, the cadet handle + * @param size number of bytes available in buf + * @param buf where the callee should write the connect message + * @return number of bytes written to buf + */ +static size_t +send_callback (void *cls, size_t size, void *buf) +{ + struct GNUNET_CADET_Handle *h = cls; + struct GNUNET_CADET_TransmitHandle *th; + struct GNUNET_CADET_TransmitHandle *next; + struct GNUNET_CADET_Channel *ch; + char *cbuf = buf; + size_t tsize; + size_t psize; + size_t nsize; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, "# Send packet() Buffer %u\n", size); + if ((0 == size) || (NULL == buf)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "# Received NULL send callback on %p\n", h); + reconnect (h); + h->th = NULL; + return 0; + } + tsize = 0; + next = h->th_head; + nsize = message_ready_size (h); + while ((NULL != (th = next)) && (0 < nsize) && (size >= nsize)) + { + ch = th->channel; + if (GNUNET_YES == th_is_payload (th)) + { + struct GNUNET_CADET_LocalData *dmsg; + struct GNUNET_MessageHeader *mh; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "# payload\n"); + if (GNUNET_NO == ch->allow_send) + { + /* This channel is not ready to transmit yet, try next message */ + next = th->next; + continue; + } + ch->packet_size = 0; + GNUNET_assert (size >= th->size); + dmsg = (struct GNUNET_CADET_LocalData *) cbuf; + mh = (struct GNUNET_MessageHeader *) &dmsg[1]; + psize = th->notify (th->notify_cls, + size - sizeof (struct GNUNET_CADET_LocalData), + mh); + if (psize > 0) + { + psize += sizeof (struct GNUNET_CADET_LocalData); + GNUNET_assert (size >= psize); + dmsg->header.size = htons (psize); + dmsg->id = htonl (ch->chid); + dmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA); + LOG (GNUNET_ERROR_TYPE_DEBUG, "# payload type %s\n", + GM_m2s (ntohs (mh->type))); + ch->allow_send = GNUNET_NO; + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "# callback returned size 0, " + "application canceled transmission\n"); + } + } + else + { + struct GNUNET_MessageHeader *mh = (struct GNUNET_MessageHeader *) &th[1]; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "# cadet internal traffic, type %s\n", + GM_m2s (ntohs (mh->type))); + memcpy (cbuf, &th[1], th->size); + psize = th->size; + } + if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (th->timeout_task); + GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th); + GNUNET_free (th); + next = h->th_head; + nsize = message_ready_size (h); + cbuf += psize; + size -= psize; + tsize += psize; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "# total size: %u\n", tsize); + h->th = NULL; + size = message_ready_size (h); + if (0 != size) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "# next size: %u\n", size); + h->th = + GNUNET_CLIENT_notify_transmit_ready (h->client, size, + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, &send_callback, h); + } + else + { + if (NULL != h->th_head) + LOG (GNUNET_ERROR_TYPE_DEBUG, "# can't transmit any more\n"); + else + LOG (GNUNET_ERROR_TYPE_DEBUG, "# nothing left to transmit\n"); + } + if (GNUNET_NO == h->in_receive) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "# start receiving from service\n"); + h->in_receive = GNUNET_YES; + GNUNET_CLIENT_receive (h->client, &msg_received, h, + GNUNET_TIME_UNIT_FOREVER_REL); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "# Send packet() END\n"); + return tsize; +} + + +/** + * Auxiliary function to send an already constructed packet to the service. + * Takes care of creating a new queue element, copying the message and + * calling the tmt_rdy function if necessary. + * + * @param h cadet handle + * @param msg message to transmit + * @param channel channel this send is related to (NULL if N/A) + */ +static void +send_packet (struct GNUNET_CADET_Handle *h, + const struct GNUNET_MessageHeader *msg, + struct GNUNET_CADET_Channel *channel) +{ + struct GNUNET_CADET_TransmitHandle *th; + size_t msize; + + LOG (GNUNET_ERROR_TYPE_DEBUG, " Sending message to service: %s\n", + GM_m2s(ntohs(msg->type))); + msize = ntohs (msg->size); + th = GNUNET_malloc (sizeof (struct GNUNET_CADET_TransmitHandle) + msize); + th->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; + th->size = msize; + th->channel = channel; + memcpy (&th[1], msg, msize); + add_to_queue (h, th); + LOG (GNUNET_ERROR_TYPE_DEBUG, " queued\n"); + if (NULL != h->th) + return; + LOG (GNUNET_ERROR_TYPE_DEBUG, " calling ntfy tmt rdy for %u bytes\n", msize); + h->th = + GNUNET_CLIENT_notify_transmit_ready (h->client, msize, + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, &send_callback, h); +} + + +/******************************************************************************/ +/********************** API CALL DEFINITIONS *************************/ +/******************************************************************************/ + +struct GNUNET_CADET_Handle * +GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, void *cls, + GNUNET_CADET_InboundChannelNotificationHandler new_channel, + GNUNET_CADET_ChannelEndHandler cleaner, + const struct GNUNET_CADET_MessageHandler *handlers, + const uint32_t *ports) +{ + struct GNUNET_CADET_Handle *h; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_CADET_connect()\n"); + h = GNUNET_new (struct GNUNET_CADET_Handle); + LOG (GNUNET_ERROR_TYPE_DEBUG, " addr %p\n", h); + h->cfg = cfg; + h->new_channel = new_channel; + h->cleaner = cleaner; + h->client = GNUNET_CLIENT_connect ("cadet", cfg); + if (h->client == NULL) + { + GNUNET_break (0); + GNUNET_free (h); + return NULL; + } + h->cls = cls; + h->message_handlers = handlers; + h->ports = ports; + h->next_chid = GNUNET_CADET_LOCAL_CHANNEL_ID_CLI; + h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS; + h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + + if (NULL != ports && ports[0] != 0 && NULL == new_channel) + { + GNUNET_break (0); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "no new channel handler given, ports parameter is useless!!\n"); + } + if ((NULL == ports || ports[0] == 0) && NULL != new_channel) + { + GNUNET_break (0); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "no ports given, new channel handler will never be called!!\n"); + } + /* count handlers */ + for (h->n_handlers = 0; + handlers && handlers[h->n_handlers].type; + h->n_handlers++) ; + for (h->n_ports = 0; + ports && ports[h->n_ports]; + h->n_ports++) ; + send_connect (h); + LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_CADET_connect() END\n"); + return h; +} + + +void +GNUNET_CADET_disconnect (struct GNUNET_CADET_Handle *handle) +{ + struct GNUNET_CADET_Channel *ch; + struct GNUNET_CADET_Channel *aux; + struct GNUNET_CADET_TransmitHandle *th; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "CADET DISCONNECT\n"); + + ch = handle->channels_head; + while (NULL != ch) + { + aux = ch->next; + if (ch->chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV) + { + GNUNET_break (0); + LOG (GNUNET_ERROR_TYPE_DEBUG, "channel %X not destroyed\n", ch->chid); + } + destroy_channel (ch, GNUNET_YES); + ch = aux; + } + while ( (th = handle->th_head) != NULL) + { + struct GNUNET_MessageHeader *msg; + + /* Make sure it is an allowed packet (everything else should have been + * already canceled). + */ + GNUNET_break (GNUNET_NO == th_is_payload (th)); + msg = (struct GNUNET_MessageHeader *) &th[1]; + switch (ntohs(msg->type)) + { + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT: + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE: + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNELS: + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL: + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER: + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS: + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL: + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS: + break; + default: + GNUNET_break (0); + LOG (GNUNET_ERROR_TYPE_ERROR, "unexpected msg %u\n", + ntohs(msg->type)); + } + + GNUNET_CONTAINER_DLL_remove (handle->th_head, handle->th_tail, th); + GNUNET_free (th); + } + + if (NULL != handle->th) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th); + handle->th = NULL; + } + if (NULL != handle->client) + { + GNUNET_CLIENT_disconnect (handle->client); + handle->client = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task) + { + GNUNET_SCHEDULER_cancel(handle->reconnect_task); + handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free (handle); +} + + +/** + * Create a new channel towards a remote peer. + * + * If the destination port is not open by any peer or the destination peer + * does not accept the channel, #GNUNET_CADET_ChannelEndHandler will be called + * for this channel. + * + * @param h cadet handle + * @param channel_ctx client's channel context to associate with the channel + * @param peer peer identity the channel should go to + * @param port Port number. + * @param options CadetOption flag field, with all desired option bits set to 1. + * + * @return handle to the channel + */ +struct GNUNET_CADET_Channel * +GNUNET_CADET_channel_create (struct GNUNET_CADET_Handle *h, + void *channel_ctx, + const struct GNUNET_PeerIdentity *peer, + uint32_t port, + enum GNUNET_CADET_ChannelOption options) +{ + struct GNUNET_CADET_Channel *ch; + struct GNUNET_CADET_ChannelMessage msg; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Creating new channel to %s:%u\n", + GNUNET_i2s (peer), port); + ch = create_channel (h, 0); + LOG (GNUNET_ERROR_TYPE_DEBUG, " at %p\n", ch); + LOG (GNUNET_ERROR_TYPE_DEBUG, " number %X\n", ch->chid); + ch->ctx = channel_ctx; + ch->peer = GNUNET_PEER_intern (peer); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE); + msg.header.size = htons (sizeof (struct GNUNET_CADET_ChannelMessage)); + msg.channel_id = htonl (ch->chid); + msg.port = htonl (port); + msg.peer = *peer; + msg.opt = htonl (options); + ch->allow_send = 0; + send_packet (h, &msg.header, ch); + return ch; +} + + +void +GNUNET_CADET_channel_destroy (struct GNUNET_CADET_Channel *channel) +{ + struct GNUNET_CADET_Handle *h; + struct GNUNET_CADET_ChannelMessage msg; + struct GNUNET_CADET_TransmitHandle *th; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying channel\n"); + h = channel->cadet; + + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY); + msg.header.size = htons (sizeof (struct GNUNET_CADET_ChannelMessage)); + msg.channel_id = htonl (channel->chid); + memset (&msg.peer, 0, sizeof (struct GNUNET_PeerIdentity)); + msg.port = 0; + msg.opt = 0; + th = h->th_head; + while (th != NULL) + { + struct GNUNET_CADET_TransmitHandle *aux; + if (th->channel == channel) + { + aux = th->next; + /* FIXME call the handler? */ + if (GNUNET_YES == th_is_payload (th)) + th->notify (th->notify_cls, 0, NULL); + GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th); + GNUNET_free (th); + th = aux; + } + else + th = th->next; + } + + destroy_channel (channel, GNUNET_YES); + send_packet (h, &msg.header, NULL); +} + + +/** + * Get information about a channel. + * + * @param channel Channel handle. + * @param option Query (GNUNET_CADET_OPTION_*). + * @param ... dependant on option, currently not used + * + * @return Union with an answer to the query. + */ +const union GNUNET_CADET_ChannelInfo * +GNUNET_CADET_channel_get_info (struct GNUNET_CADET_Channel *channel, + enum GNUNET_CADET_ChannelOption option, ...) +{ + static int bool_flag; + const union GNUNET_CADET_ChannelInfo *ret; + + switch (option) + { + case GNUNET_CADET_OPTION_NOBUFFER: + case GNUNET_CADET_OPTION_RELIABLE: + case GNUNET_CADET_OPTION_OOORDER: + if (0 != (option & channel->options)) + bool_flag = GNUNET_YES; + else + bool_flag = GNUNET_NO; + ret = (const union GNUNET_CADET_ChannelInfo *) &bool_flag; + break; + case GNUNET_CADET_OPTION_PEER: + ret = (const union GNUNET_CADET_ChannelInfo *) GNUNET_PEER_resolve2 (channel->peer); + break; + default: + GNUNET_break (0); + return NULL; + } + + return ret; +} + +struct GNUNET_CADET_TransmitHandle * +GNUNET_CADET_notify_transmit_ready (struct GNUNET_CADET_Channel *channel, int cork, + struct GNUNET_TIME_Relative maxdelay, + size_t notify_size, + GNUNET_CONNECTION_TransmitReadyNotify notify, + void *notify_cls) +{ + struct GNUNET_CADET_TransmitHandle *th; + + GNUNET_assert (NULL != channel); + LOG (GNUNET_ERROR_TYPE_DEBUG, "CADET NOTIFY TRANSMIT READY\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X\n", channel->chid); + LOG (GNUNET_ERROR_TYPE_DEBUG, " allow_send %d\n", channel->allow_send); + if (channel->chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV) + LOG (GNUNET_ERROR_TYPE_DEBUG, " to origin\n"); + else + LOG (GNUNET_ERROR_TYPE_DEBUG, " to destination\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, " payload size %u\n", notify_size); + GNUNET_assert (NULL != notify); + GNUNET_assert (0 == channel->packet_size); // Only one data packet allowed + th = GNUNET_new (struct GNUNET_CADET_TransmitHandle); + th->channel = channel; + th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay); + th->size = notify_size + sizeof (struct GNUNET_CADET_LocalData); + channel->packet_size = th->size; + LOG (GNUNET_ERROR_TYPE_DEBUG, " total size %u\n", th->size); + th->notify = notify; + th->notify_cls = notify_cls; + add_to_queue (channel->cadet, th); + if (NULL != channel->cadet->th) + return th; + if (GNUNET_NO == channel->allow_send) + return th; + LOG (GNUNET_ERROR_TYPE_DEBUG, " call client notify tmt rdy\n"); + channel->cadet->th = + GNUNET_CLIENT_notify_transmit_ready (channel->cadet->client, th->size, + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, &send_callback, + channel->cadet); + LOG (GNUNET_ERROR_TYPE_DEBUG, "CADET NOTIFY TRANSMIT READY END\n"); + return th; +} + + +void +GNUNET_CADET_notify_transmit_ready_cancel (struct GNUNET_CADET_TransmitHandle *th) +{ + struct GNUNET_CADET_Handle *cadet; + + th->channel->packet_size = 0; + cadet = th->channel->cadet; + if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (th->timeout_task); + GNUNET_CONTAINER_DLL_remove (cadet->th_head, cadet->th_tail, th); + GNUNET_free (th); + if ((0 == message_ready_size (cadet)) && (NULL != cadet->th)) + { + /* queue empty, no point in asking for transmission */ + GNUNET_CLIENT_notify_transmit_ready_cancel (cadet->th); + cadet->th = NULL; + } +} + + +void +GNUNET_CADET_receive_done (struct GNUNET_CADET_Channel *channel) +{ + send_ack (channel); +} + + +static void +send_info_request (struct GNUNET_CADET_Handle *h, uint16_t type) +{ + struct GNUNET_MessageHeader msg; + + msg.size = htons (sizeof (msg)); + msg.type = htons (type); + send_packet (h, &msg, NULL); +} + + +/** + * Request information about peers known to the running cadet service. + * The callback will be called for every peer known to the service. + * Only one info request (of any kind) can be active at once. + * + * + * WARNING: unstable API, likely to change in the future! + * + * @param h Handle to the cadet peer. + * @param callback Function to call with the requested data. + * @param callback_cls Closure for @c callback. + * + * @return #GNUNET_OK / #GNUNET_SYSERR + */ +int +GNUNET_CADET_get_peers (struct GNUNET_CADET_Handle *h, + GNUNET_CADET_PeersCB callback, + void *callback_cls) +{ + if (NULL != h->info_cb.peers_cb) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + send_info_request (h, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS); + h->info_cb.peers_cb = callback; + h->info_cls = callback_cls; + return GNUNET_OK; +} + + +/** + * Cancel a peer info request. The callback will not be called (anymore). + * + * WARNING: unstable API, likely to change in the future! + * + * @param h Cadet handle. + * + * @return Closure given to GNUNET_CADET_get_peers. + */ +void * +GNUNET_CADET_get_peers_cancel (struct GNUNET_CADET_Handle *h) +{ + void *cls; + + cls = h->info_cls; + h->info_cb.peers_cb = NULL; + h->info_cls = NULL; + return cls; +} + + +/** + * Request information about a peer known to the running cadet peer. + * The callback will be called for the tunnel once. + * Only one info request (of any kind) can be active at once. + * + * WARNING: unstable API, likely to change in the future! + * + * @param h Handle to the cadet peer. + * @param id Peer whose tunnel to examine. + * @param callback Function to call with the requested data. + * @param callback_cls Closure for @c callback. + * + * @return #GNUNET_OK / #GNUNET_SYSERR + */ +int +GNUNET_CADET_get_peer (struct GNUNET_CADET_Handle *h, + const struct GNUNET_PeerIdentity *id, + GNUNET_CADET_PeerCB callback, + void *callback_cls) +{ + struct GNUNET_CADET_LocalInfo msg; + + if (NULL != h->info_cb.peer_cb) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + memset (&msg, 0, sizeof (msg)); + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER); + msg.peer = *id; + send_packet (h, &msg.header, NULL); + h->info_cb.peer_cb = callback; + h->info_cls = callback_cls; + return GNUNET_OK; +} + + +/** + * Request information about tunnels of the running cadet peer. + * The callback will be called for every tunnel of the service. + * Only one info request (of any kind) can be active at once. + * + * WARNING: unstable API, likely to change in the future! + * + * @param h Handle to the cadet peer. + * @param callback Function to call with the requested data. + * @param callback_cls Closure for @c callback. + * + * @return #GNUNET_OK / #GNUNET_SYSERR + */ +int +GNUNET_CADET_get_tunnels (struct GNUNET_CADET_Handle *h, + GNUNET_CADET_TunnelsCB callback, + void *callback_cls) +{ + if (NULL != h->info_cb.tunnels_cb) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + send_info_request (h, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS); + h->info_cb.tunnels_cb = callback; + h->info_cls = callback_cls; + return GNUNET_OK; +} + + +/** + * Cancel a monitor request. The monitor callback will not be called. + * + * @param h Cadet handle. + * + * @return Closure given to GNUNET_CADET_get_tunnels. + */ +void * +GNUNET_CADET_get_tunnels_cancel (struct GNUNET_CADET_Handle *h) +{ + void *cls; + + h->info_cb.tunnels_cb = NULL; + cls = h->info_cls; + h->info_cls = NULL; + + return cls; +} + + + +/** + * Request information about a tunnel of the running cadet peer. + * The callback will be called for the tunnel once. + * Only one info request (of any kind) can be active at once. + * + * WARNING: unstable API, likely to change in the future! + * + * @param h Handle to the cadet peer. + * @param id Peer whose tunnel to examine. + * @param callback Function to call with the requested data. + * @param callback_cls Closure for @c callback. + * + * @return #GNUNET_OK / #GNUNET_SYSERR + */ +int +GNUNET_CADET_get_tunnel (struct GNUNET_CADET_Handle *h, + const struct GNUNET_PeerIdentity *id, + GNUNET_CADET_TunnelCB callback, + void *callback_cls) +{ + struct GNUNET_CADET_LocalInfo msg; + + if (NULL != h->info_cb.tunnel_cb) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + memset (&msg, 0, sizeof (msg)); + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL); + msg.peer = *id; + send_packet (h, &msg.header, NULL); + h->info_cb.tunnel_cb = callback; + h->info_cls = callback_cls; + return GNUNET_OK; +} + + +/** + * Request information about a specific channel of the running cadet peer. + * + * WARNING: unstable API, likely to change in the future! + * FIXME Add destination option. + * + * @param h Handle to the cadet peer. + * @param initiator ID of the owner of the channel. + * @param channel_number Channel number. + * @param callback Function to call with the requested data. + * @param callback_cls Closure for @c callback. + * + * @return #GNUNET_OK / #GNUNET_SYSERR + */ +int +GNUNET_CADET_show_channel (struct GNUNET_CADET_Handle *h, + struct GNUNET_PeerIdentity *initiator, + unsigned int channel_number, + GNUNET_CADET_ChannelCB callback, + void *callback_cls) +{ + struct GNUNET_CADET_LocalInfo msg; + + if (NULL != h->info_cb.channel_cb) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL); + msg.peer = *initiator; + msg.channel_id = htonl (channel_number); +// msg.reserved = 0; + send_packet (h, &msg.header, NULL); + h->info_cb.channel_cb = callback; + h->info_cls = callback_cls; + return GNUNET_OK; +} + + +/** + * Function called to notify a client about the connection + * begin ready to queue more data. "buf" will be + * NULL and "size" zero if the connection 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 +cadet_mq_ntr (void *cls, size_t size, + void *buf) +{ + struct GNUNET_MQ_Handle *mq = cls; + struct CadetMQState *state = GNUNET_MQ_impl_state (mq); + const struct GNUNET_MessageHeader *msg = GNUNET_MQ_impl_current (mq); + uint16_t msize; + + state->th = NULL; + if (NULL == buf) + { + GNUNET_MQ_inject_error (mq, GNUNET_MQ_ERROR_WRITE); + return 0; + } + msize = ntohs (msg->size); + GNUNET_assert (msize <= size); + memcpy (buf, msg, msize); + GNUNET_MQ_impl_send_continue (mq); + return msize; +} + + +/** + * Signature of functions implementing the + * sending functionality of a message queue. + * + * @param mq the message queue + * @param msg the message to send + * @param impl_state state of the implementation + */ +static void +cadet_mq_send_impl (struct GNUNET_MQ_Handle *mq, + const struct GNUNET_MessageHeader *msg, void *impl_state) +{ + struct CadetMQState *state = impl_state; + + GNUNET_assert (NULL == state->th); + state->th = + GNUNET_CADET_notify_transmit_ready (state->channel, + /* FIXME: add option for corking */ + GNUNET_NO, + GNUNET_TIME_UNIT_FOREVER_REL, + ntohs (msg->size), + cadet_mq_ntr, mq); + +} + + +/** + * Signature of functions implementing the + * destruction of a message queue. + * Implementations must not free 'mq', but should + * take care of 'impl_state'. + * + * @param mq the message queue to destroy + * @param impl_state state of the implementation + */ +static void +cadet_mq_destroy_impl (struct GNUNET_MQ_Handle *mq, void *impl_state) +{ + struct CadetMQState *state = impl_state; + + if (NULL != state->th) + GNUNET_CADET_notify_transmit_ready_cancel (state->th); + + GNUNET_free (state); +} + + +/** + * Create a message queue for a cadet channel. + * The message queue can only be used to transmit messages, + * not to receive them. + * + * @param channel the channel to create the message qeue for + * @return a message queue to messages over the channel + */ +struct GNUNET_MQ_Handle * +GNUNET_CADET_mq_create (struct GNUNET_CADET_Channel *channel) +{ + struct GNUNET_MQ_Handle *mq; + struct CadetMQState *state; + + state = GNUNET_new (struct CadetMQState); + state->channel = channel; + + mq = GNUNET_MQ_queue_for_callbacks (cadet_mq_send_impl, + cadet_mq_destroy_impl, + NULL, /* FIXME: cancel impl. */ + state, + NULL, /* no msg handlers */ + NULL, /* no err handlers */ + NULL); /* no handler cls */ + return mq; +} + diff --git a/src/cadet/cadet_common.c b/src/cadet/cadet_common.c new file mode 100644 index 000000000..855e9e20c --- /dev/null +++ b/src/cadet/cadet_common.c @@ -0,0 +1,348 @@ +/* + This file is part of GNUnet. + (C) 2012 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 cadet/cadet_common.c + * @brief CADET helper functions + * @author Bartlomiej Polot + */ + +#include "cadet.h" + +/** + * @brief Translate a fwd variable into a string representation, for logging. + * + * @param fwd Is FWD? (#GNUNET_YES or #GNUNET_NO) + * + * @return String representing FWD or BCK. + */ +char * +GM_f2s (int fwd) +{ + if (GNUNET_YES == fwd) + { + return "FWD"; + } + else if (GNUNET_NO == fwd) + { + return "BCK"; + } + else + { + /* Not an error, can happen with CONNECTION_BROKEN messages. */ + return ""; + } +} + +int +GM_is_pid_bigger (uint32_t bigger, uint32_t smaller) +{ + return (GNUNET_YES == PID_OVERFLOW (smaller, bigger) || + (bigger > smaller && GNUNET_NO == PID_OVERFLOW (bigger, smaller))); +} + + +uint32_t +GM_max_pid (uint32_t a, uint32_t b) +{ + if (GM_is_pid_bigger(a, b)) + return a; + return b; +} + + +uint32_t +GM_min_pid (uint32_t a, uint32_t b) +{ + if (GM_is_pid_bigger(a, b)) + return b; + return a; +} + + +const struct GNUNET_HashCode * +GM_h2hc (const struct GNUNET_CADET_Hash *id) +{ + static struct GNUNET_HashCode hc; + memcpy (&hc, id, sizeof (*id)); + + return &hc; +} + + +const char * +GM_h2s (const struct GNUNET_CADET_Hash *id) +{ + static char s[53]; + + memcpy (s, GNUNET_h2s_full (GM_h2hc (id)), 52); + s[52] = '\0'; + + return s; +} + + +#if !defined(GNUNET_CULL_LOGGING) +const char * +GM_m2s (uint16_t m) +{ + static char buf[32]; + const char *t; + + switch (m) + { + /** + * Request the creation of a path + */ + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE: + t = "CONNECTION_CREATE"; + break; + + /** + * Request the modification of an existing path + */ + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK: + t = "CONNECTION_ACK"; + break; + + /** + * Notify that a connection of a path is no longer valid + */ + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN: + t = "CONNECTION_BROKEN"; + break; + + /** + * At some point, the route will spontaneously change + */ + case GNUNET_MESSAGE_TYPE_CADET_PATH_CHANGED: + t = "PATH_CHANGED"; + break; + + /** + * Transport payload data. + */ + case GNUNET_MESSAGE_TYPE_CADET_DATA: + t = "DATA"; + break; + + /** + * Confirm receipt of payload data. + */ + case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK: + t = "DATA_ACK"; + break; + + /** + * Key exchange encapsulation. + */ + case GNUNET_MESSAGE_TYPE_CADET_KX: + t = "KX"; + break; + + /** + * New ephemeral key. + */ + case GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL: + t = "KX_EPHEMERAL"; + break; + + /** + * Challenge to test peer's session key. + */ + case GNUNET_MESSAGE_TYPE_CADET_KX_PING: + t = "KX_PING"; + break; + + /** + * Answer to session key challenge. + */ + case GNUNET_MESSAGE_TYPE_CADET_KX_PONG: + t = "KX_PONG"; + break; + + /** + * Request the destuction of a path + */ + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY: + t = "CONNECTION_DESTROY"; + break; + + /** + * ACK for a data packet. + */ + case GNUNET_MESSAGE_TYPE_CADET_ACK: + t = "ACK"; + break; + + /** + * POLL for ACK. + */ + case GNUNET_MESSAGE_TYPE_CADET_POLL: + t = "POLL"; + break; + + /** + * Announce origin is still alive. + */ + case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE: + t = "KEEPALIVE"; + break; + + /** + * Connect to the cadet service, specifying subscriptions + */ + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT: + t = "LOCAL_CONNECT"; + break; + + /** + * Ask the cadet service to create a new tunnel + */ + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE: + t = "CHANNEL_CREATE"; + break; + + /** + * Ask the cadet service to destroy a tunnel + */ + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: + t = "CHANNEL_DESTROY"; + break; + + /** + * Confirm the creation of a channel. + */ + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK: + t = "CHANNEL_ACK"; + break; + + /** + * Confirm the creation of a channel. + */ + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK: + t = "CHANNEL_NACK"; + break; + + /** + * Encrypted payload. + */ + case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED: + t = "ENCRYPTED"; + break; + + /** + * Local payload traffic + */ + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA: + t = "LOCAL_DATA"; + break; + + /** + * Local ACK for data. + */ + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK: + t = "LOCAL_ACK"; + break; + + /** + * Local monitoring of channels. + */ + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNELS: + t = "LOCAL_INFO_CHANNELS"; + break; + + /** + * Local monitoring of a channel. + */ + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL: + t = "LOCAL_INFO_CHANNEL"; + break; + + /** + * Local monitoring of service. + */ + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS: + t = "LOCAL_INFO_TUNNELS"; + break; + + /** + * Local monitoring of service. + */ + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL: + t = "LOCAL_INFO_TUNNEL"; + break; + + /** + * Local information about all connections of service. + */ + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CONNECTIONS: + t = "LOCAL_INFO_CONNECTIONS"; + break; + + /** + * Local information of service about a specific connection. + */ + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CONNECTION: + t = "LOCAL_INFO_CONNECTION"; + break; + + /** + * Local information about all peers known to the service. + */ + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS: + t = "LOCAL_INFO_PEERS"; + break; + + /** + * Local information of service about a specific peer. + */ + case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER: + t = "LOCAL_INFO_PEER"; + break; + + /** + * Traffic (net-cat style) used by the Command Line Interface. + */ + case GNUNET_MESSAGE_TYPE_CADET_CLI: + t = "CLI"; + break; + + /** + * 640kb should be enough for everybody + */ + case 299: + t = "RESERVE_END"; + break; + + default: + sprintf(buf, "%u (UNKNOWN TYPE)", m); + return buf; + } + sprintf(buf, "{%18s}", t); + return buf; +} +#else +const char * +GM_m2s (uint16_t m) +{ + return ""; +} +#endif diff --git a/src/cadet/cadet_path.c b/src/cadet/cadet_path.c new file mode 100644 index 000000000..0a97e73ef --- /dev/null +++ b/src/cadet/cadet_path.c @@ -0,0 +1,213 @@ +/* + This file is part of GNUnet. + (C) 2001 - 2013 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 cadet/cadet_path.c + * @brief Path handling functions + * @author Bartlomiej Polot + */ + +#include "cadet.h" +#include "cadet_path.h" +#include "gnunet-service-cadet_peer.h" + +/** + * @brief Destroy a path after some time has past. + * + * If the path is returned from DHT again after a while, try again. + * + * @param cls Closure (path to destroy). + * @param tc Task context. + */ +static void +path_destroy_delayed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CadetPeerPath *path = cls; + struct CadetPeer *peer; + + path->path_delete = GNUNET_SCHEDULER_NO_TASK; + peer = GMP_get_short (path->peers[path->length - 1]); + GMP_remove_path (peer, path); +} + + +/** + * Create a new path + * + * @param length How many hops will the path have. + * + * @return A newly allocated path with a peer array of the specified length. + */ +struct CadetPeerPath * +path_new (unsigned int length) +{ + struct CadetPeerPath *p; + + p = GNUNET_new (struct CadetPeerPath); + if (length > 0) + { + p->length = length; + p->peers = GNUNET_malloc (length * sizeof (GNUNET_PEER_Id)); + } + return p; +} + + +/** + * Invert the path + * + * @param path the path to invert + */ +void +path_invert (struct CadetPeerPath *path) +{ + GNUNET_PEER_Id aux; + unsigned int i; + + for (i = 0; i < path->length / 2; i++) + { + aux = path->peers[i]; + path->peers[i] = path->peers[path->length - i - 1]; + path->peers[path->length - i - 1] = aux; + } +} + + +/** + * Duplicate a path, incrementing short peer's rc. + * + * @param path The path to duplicate. + */ +struct CadetPeerPath * +path_duplicate (const struct CadetPeerPath *path) +{ + struct CadetPeerPath *aux; + unsigned int i; + + aux = path_new (path->length); + memcpy (aux->peers, path->peers, path->length * sizeof (GNUNET_PEER_Id)); + for (i = 0; i < aux->length; i++) + GNUNET_PEER_change_rc (aux->peers[i], 1); + return aux; +} + + +/** + * Get the length of a path. + * + * @param path The path to measure, with the local peer at any point of it. + * + * @return Number of hops to reach destination. + * UINT_MAX in case the peer is not in the path. + */ +unsigned int +path_get_length (struct CadetPeerPath *path) +{ + if (NULL == path) + return UINT_MAX; + return path->length; +} + + + +/** + * Mark path as invalid: keep it aroud for a while to avoid trying it in a loop. + * + * DHT_get sometimes returns bad cached results, for instance, on a locally + * cached result where the PUT followed a path that is no longer current. + * + * @param p Path to invalidate. + */ +void +path_invalidate (struct CadetPeerPath *p) +{ + if (GNUNET_SCHEDULER_NO_TASK != p->path_delete) + return; + + p->path_delete = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, + &path_destroy_delayed, p); +} + + +/** + * Test if a path is valid (or at least not known to be invalid). + * + * @param path Path to test. + * + * @return #GNUNET_YES If the path is valid or unknown, + * #GNUNET_NO If the path is known to be invalid. + */ +int +path_is_valid (const struct CadetPeerPath *path) +{ + return (GNUNET_SCHEDULER_NO_TASK == path->path_delete); +} + + +/** + * Destroy the path and free any allocated resources linked to it + * + * @param p the path to destroy + * + * @return GNUNET_OK on success + */ +int +path_destroy (struct CadetPeerPath *p) +{ + if (NULL == p) + return GNUNET_OK; + + GNUNET_PEER_decrement_rcs (p->peers, p->length); + GNUNET_free_non_null (p->peers); + if (GNUNET_SCHEDULER_NO_TASK != p->path_delete) + GNUNET_SCHEDULER_cancel (p->path_delete); + GNUNET_free (p); + return GNUNET_OK; +} + +char * +path_2s (struct CadetPeerPath *p) +{ + char *s; + char *old; + unsigned int i; + + old = GNUNET_strdup (""); + for (i = 0; i < p->length; i++) + { + GNUNET_asprintf (&s, "%s %s", + old, GNUNET_i2s (GNUNET_PEER_resolve2 (p->peers[i]))); + GNUNET_free_non_null (old); + old = s; + } + return s; +} + +void +path_debug (struct CadetPeerPath *p) +{ + unsigned int i; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "PATH:\n"); + for (i = 0; i < p->length; i++) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %s\n", + GNUNET_i2s (GNUNET_PEER_resolve2 (p->peers[i]))); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "END\n"); +} diff --git a/src/cadet/cadet_path.h b/src/cadet/cadet_path.h new file mode 100644 index 000000000..36bcfa5ae --- /dev/null +++ b/src/cadet/cadet_path.h @@ -0,0 +1,185 @@ +/* + This file is part of GNUnet. + (C) 2001 - 2013 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 cadet/cadet_path.h + * @brief Path handling functions + * @author Bartlomiej Polot + */ + +#include "gnunet-service-cadet_connection.h" + +#ifndef CADET_PATH_H_ +#define CADET_PATH_H_ + +#ifdef __cplusplus +extern "C" +{ + #if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +/******************************************************************************/ +/************************ DATA STRUCTURES ****************************/ +/******************************************************************************/ + +/** + * Information regarding a possible path to reach a single peer + */ +struct CadetPeerPath +{ + + /** + * Linked list + */ + struct CadetPeerPath *next; + struct CadetPeerPath *prev; + + /** + * List of all the peers that form the path from origin to target. + */ + GNUNET_PEER_Id *peers; + + /** + * Number of peers (hops) in the path + */ + unsigned int length; + + /** + * User defined data store. + */ + struct CadetConnection *c; + + /** + * Path's score, how reliable is the path. + */ +// int score; + + /** + * Task to delete the path. + * We tried it, it didn't work, don't try again in a while. + */ + GNUNET_SCHEDULER_TaskIdentifier path_delete; + +}; + +/******************************************************************************/ +/************************* FUNCTIONS *****************************/ +/******************************************************************************/ + +/** + * Create a new path. + * + * @param length How many hops will the path have. + * + * @return A newly allocated path with a peer array of the specified length. + */ +struct CadetPeerPath * +path_new (unsigned int length); + + +/** + * Invert the path. + * + * @param path The path to invert. + */ +void +path_invert (struct CadetPeerPath *path); + + +/** + * Duplicate a path, incrementing short peer's rc. + * + * @param path The path to duplicate. + */ +struct CadetPeerPath * +path_duplicate (const struct CadetPeerPath *path); + + +/** + * Get the length of a path. + * + * @param path The path to measure, with the local peer at any point of it. + * + * @return Number of hops to reach destination. + * UINT_MAX in case the peer is not in the path. + */ +unsigned int +path_get_length (struct CadetPeerPath *path); + +/** + * Mark path as invalid: keep it aroud for a while to avoid trying it in a loop. + * + * DHT_get sometimes returns bad cached results, for instance, on a locally + * cached result where the PUT followed a path that is no longer current. + * + * @param p Path to invalidate. + */ +void +path_invalidate (struct CadetPeerPath *p); + +/** + * Test if a path is valid (or at least not known to be invalid). + * + * @param path Path to test. + * + * @return #GNUNET_YES If the path is valid or unknown, + * #GNUNET_NO If the path is known to be invalid. + */ +int +path_is_valid (const struct CadetPeerPath *path); + +/** + * Destroy the path and free any allocated resources linked to it + * + * @param p the path to destroy + * + * @return GNUNET_OK on success + */ +int +path_destroy (struct CadetPeerPath *p); + +/** + * Path -> allocated one line string. Caller must free. + * + * @param p Path. + */ +char * +path_2s (struct CadetPeerPath *p); + +/** + * Print info about the path for debug. + * + * @param p Path to debug. + */ +void +path_debug (struct CadetPeerPath *p); + +#if 0 /* keep Emacsens' auto-indent happy */ +{ + #endif + #ifdef __cplusplus +} +#endif + + +/* ifndef CADET_PATH_H */ +#endif diff --git a/src/cadet/cadet_protocol.h b/src/cadet/cadet_protocol.h new file mode 100644 index 000000000..19cdfe4a0 --- /dev/null +++ b/src/cadet/cadet_protocol.h @@ -0,0 +1,459 @@ +/* + This file is part of GNUnet. + (C) 2001 - 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. +*/ + +/** + * @author Bartlomiej Polot + * @file cadet/cadet_protocol.h + */ + +#ifndef CADET_PROTOCOL_H_ +#define CADET_PROTOCOL_H_ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "cadet.h" + +#ifdef __cplusplus + +struct GNUNET_CADET_TunnelMessage; +extern "C" +{ +#if 0 + /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +/******************************************************************************/ +/******************** CADET NETWORK MESSAGES **************************/ +/******************************************************************************/ + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message for cadet connection creation. + */ +struct GNUNET_CADET_ConnectionCreate +{ + /** + * Type: GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE + * + * Size: sizeof (struct GNUNET_CADET_ConnectionCreate) + + * path_length * sizeof (struct GNUNET_PeerIdentity) + */ + struct GNUNET_MessageHeader header; + + /** + * ID of the connection + */ + struct GNUNET_CADET_Hash cid; + + /** + * path_length structs defining the *whole* path from the origin [0] to the + * final destination [path_length-1]. + */ + /* struct GNUNET_PeerIdentity peers[path_length]; */ +}; + +/** + * Message for ack'ing a connection + */ +struct GNUNET_CADET_ConnectionACK +{ + /** + * Type: GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK + */ + struct GNUNET_MessageHeader header; + + /** + * ID of the connection. + */ + struct GNUNET_CADET_Hash cid; + +}; + + +/** + * Message for encapsulation of a Key eXchange message in a connection. + */ +struct GNUNET_CADET_KX +{ + /** + * Type: GNUNET_MESSAGE_TYPE_CADET_KX. + */ + struct GNUNET_MessageHeader header; + + /** + * ID of the connection. + */ + struct GNUNET_CADET_Hash cid; + + /* Specific KX message follows. */ +}; + + +/** + * Message transmitted with the signed ephemeral key of a peer. The + * session key is then derived from the two ephemeral keys (ECDHE). + * + * As far as possible, same as CORE's EphemeralKeyMessage. + */ +struct GNUNET_CADET_KX_Ephemeral +{ + + /** + * Message type is GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL. + */ + struct GNUNET_MessageHeader header; + + /** + * Status of the sender (should be in "enum PeerStateMachine"), nbo. + */ + int32_t sender_status GNUNET_PACKED; + + /** + * An ECC signature of the 'origin' asserting the validity of + * the given ephemeral key. + */ + struct GNUNET_CRYPTO_EddsaSignature signature; + + /** + * Information about what is being signed. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * At what time was this key created (beginning of validity). + */ + struct GNUNET_TIME_AbsoluteNBO creation_time; + + /** + * When does the given ephemeral key expire (end of validity). + */ + struct GNUNET_TIME_AbsoluteNBO expiration_time; + + /** + * Ephemeral public ECC key (always for NIST P-521) encoded in a format suitable + * for network transmission as created using 'gcry_sexp_sprint'. + */ + struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key; + + /** + * Public key of the signing peer (persistent version, not the ephemeral public key). + */ + struct GNUNET_PeerIdentity origin_identity; +}; + + +/** + * We're sending an (encrypted) PING to the other peer to check if he + * can decrypt. The other peer should respond with a PONG with the + * same content, except this time encrypted with the receiver's key. + */ +struct GNUNET_CADET_KX_Ping +{ + /** + * Message type is GNUNET_MESSAGE_TYPE_CADET_KX_PING. + */ + struct GNUNET_MessageHeader header; + + /** + * Seed for the IV + */ + uint32_t iv GNUNET_PACKED; + + /** + * Intended target of the PING, used primarily to check + * that decryption actually worked. + */ + struct GNUNET_PeerIdentity target; + + /** + * Random number chosen to make reply harder. + */ + uint32_t nonce GNUNET_PACKED; +}; + + +/** + * Response to a PING. Includes data from the original PING. + */ +struct GNUNET_CADET_KX_Pong +{ + /** + * Message type is GNUNET_MESSAGE_TYPE_CADET_KX_PONG. + */ + struct GNUNET_MessageHeader header; + + /** + * Seed for the IV + */ + uint32_t iv GNUNET_PACKED; + + /** + * Same nonce as in the reve. + */ + uint32_t nonce GNUNET_PACKED; +}; + + +/** + * Tunnel(ed) message. + */ +struct GNUNET_CADET_Encrypted +{ + /** + * Type: GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED + */ + struct GNUNET_MessageHeader header; + + /** + * ID of the connection. + */ + struct GNUNET_CADET_Hash cid; + + /** + * ID of the packet (hop by hop). + */ + uint32_t pid GNUNET_PACKED; + + /** + * Number of hops to live. + */ + uint32_t ttl GNUNET_PACKED; + + /** + * Initialization Vector for payload encryption. + */ + uint32_t iv GNUNET_PACKED; + + /** + * MAC of the encrypted message, used to verify message integrity. + * Everything after this value will be encrypted and authenticated. + */ + struct GNUNET_CADET_Hash hmac; + + /** + * Encrypted content follows. + */ +}; + + +/** + * Message to create a Channel. + */ +struct GNUNET_CADET_ChannelCreate +{ + /** + * Type: GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE + */ + struct GNUNET_MessageHeader header; + + /** + * ID of the channel + */ + CADET_ChannelNumber chid GNUNET_PACKED; + + /** + * Destination port. + */ + uint32_t port GNUNET_PACKED; + + /** + * Channel options. + */ + uint32_t opt GNUNET_PACKED; +}; + + +/** + * Message to manage a Channel (ACK, NACK, Destroy). + */ +struct GNUNET_CADET_ChannelManage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_CADET_CHANNEL_{ACK|NACK|DESTROY} + */ + struct GNUNET_MessageHeader header; + + /** + * ID of the channel + */ + CADET_ChannelNumber chid GNUNET_PACKED; +}; + + +/** + * Message for cadet data traffic. + */ +struct GNUNET_CADET_Data +{ + /** + * Type: GNUNET_MESSAGE_TYPE_CADET_UNICAST, + * GNUNET_MESSAGE_TYPE_CADET_TO_ORIGIN + */ + struct GNUNET_MessageHeader header; + + /** + * Unique ID of the payload message + */ + uint32_t mid GNUNET_PACKED; + + /** + * ID of the channel + */ + CADET_ChannelNumber chid GNUNET_PACKED; + + /** + * Payload follows + */ +}; + + +/** + * Message to acknowledge end-to-end data. + */ +struct GNUNET_CADET_DataACK +{ + /** + * Type: GNUNET_MESSAGE_TYPE_CADET_DATA_ACK + */ + struct GNUNET_MessageHeader header; + + /** + * ID of the channel + */ + CADET_ChannelNumber chid GNUNET_PACKED; + + /** + * Bitfield of already-received newer messages + * pid + 1 @ LSB + * pid + 64 @ MSB + */ + uint64_t futures GNUNET_PACKED; + + /** + * Last message ID received. + */ + uint32_t mid GNUNET_PACKED; +}; + + +/** + * Message to acknowledge cadet encrypted traffic. + */ +struct GNUNET_CADET_ACK +{ + /** + * Type: GNUNET_MESSAGE_TYPE_CADET_ACK + */ + struct GNUNET_MessageHeader header; + + /** + * Maximum packet ID authorized. + */ + uint32_t ack GNUNET_PACKED; + + /** + * ID of the connection. + */ + struct GNUNET_CADET_Hash cid; +}; + + +/** + * Message to query a peer about its Flow Control status regarding a tunnel. + */ +struct GNUNET_CADET_Poll +{ + /** + * Type: GNUNET_MESSAGE_TYPE_CADET_POLL + */ + struct GNUNET_MessageHeader header; + + /** + * Last packet sent. + */ + uint32_t pid GNUNET_PACKED; + + /** + * ID of the connection. + */ + struct GNUNET_CADET_Hash cid; + +}; + + +/** + * Message for notifying a disconnection in a path + */ +struct GNUNET_CADET_ConnectionBroken +{ + /** + * Type: GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN + */ + struct GNUNET_MessageHeader header; + + /** + * ID of the connection. + */ + struct GNUNET_CADET_Hash cid; + + /** + * ID of the endpoint + */ + struct GNUNET_PeerIdentity peer1; + + /** + * ID of the endpoint + */ + struct GNUNET_PeerIdentity peer2; +}; + + +/** + * Message to destroy a connection. + */ +struct GNUNET_CADET_ConnectionDestroy +{ + /** + * Type: GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY + */ + struct GNUNET_MessageHeader header; + + /** + * ID of the connection. + */ + struct GNUNET_CADET_Hash cid; +}; + + +GNUNET_NETWORK_STRUCT_END + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef CADET_PROTOCOL_H */ +#endif +/* end of cadet_protocol.h */ diff --git a/src/cadet/cadet_test_lib.c b/src/cadet/cadet_test_lib.c new file mode 100644 index 000000000..663972cad --- /dev/null +++ b/src/cadet/cadet_test_lib.c @@ -0,0 +1,295 @@ +/* + This file is part of GNUnet. + (C) 2012 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 cadet/cadet_test_lib.c + * @author Bartlomiej Polot + * @brief library for writing CADET tests + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "cadet_test_lib.h" +#include "gnunet_cadet_service.h" + +/** + * Test context for a CADET Test. + */ +struct GNUNET_CADET_TEST_Context +{ + /** + * Array of running peers. + */ + struct GNUNET_TESTBED_Peer **peers; + + /** + * Array of handles to the CADET for each peer. + */ + struct GNUNET_CADET_Handle **cadetes; + + /** + * Operation associated with the connection to the CADET. + */ + struct GNUNET_TESTBED_Operation **ops; + + /** + * Main function of the test to run once all CADETs are available. + */ + GNUNET_CADET_TEST_AppMain app_main; + + /** + * Closure for 'app_main'. + */ + void *app_main_cls; + + /** + * Number of peers running, size of the arrays above. + */ + unsigned int num_peers; + + /** + * Handler for incoming tunnels. + */ + GNUNET_CADET_InboundChannelNotificationHandler *new_channel; + + /** + * Cleaner for destroyed incoming tunnels. + */ + GNUNET_CADET_ChannelEndHandler *cleaner; + + /** + * Message handlers. + */ + struct GNUNET_CADET_MessageHandler* handlers; + + /** + * Application ports. + */ + const uint32_t *ports; + +}; + + +/** + * Context for a cadet adapter callback. + */ +struct GNUNET_CADET_TEST_AdapterContext +{ + /** + * Peer number for the particular peer. + */ + unsigned int peer; + + /** + * General context. + */ + struct GNUNET_CADET_TEST_Context *ctx; +}; + + +/** + * Adapter function called to establish a connection to + * the CADET service. + * + * @param cls closure + * @param cfg configuration of the peer to connect to; will be available until + * GNUNET_TESTBED_operation_done() is called on the operation returned + * from GNUNET_TESTBED_service_connect() + * @return service handle to return in 'op_result', NULL on error + */ +static void * +cadet_connect_adapter (void *cls, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_CADET_TEST_AdapterContext *actx = cls; + struct GNUNET_CADET_TEST_Context *ctx = actx->ctx; + struct GNUNET_CADET_Handle *h; + + h = GNUNET_CADET_connect (cfg, + (void *) (long) actx->peer, + ctx->new_channel, + ctx->cleaner, + ctx->handlers, + ctx->ports); + return h; +} + + +/** + * Adapter function called to destroy a connection to + * the CADET service. + * + * @param cls closure + * @param op_result service handle returned from the connect adapter + */ +static void +cadet_disconnect_adapter (void *cls, + void *op_result) +{ + struct GNUNET_CADET_Handle *cadet = op_result; + struct GNUNET_CADET_TEST_AdapterContext *actx = cls; + + GNUNET_free (actx); + GNUNET_CADET_disconnect (cadet); +} + + +/** + * Callback to be called when a service connect operation is completed. + * + * @param cls The callback closure from functions generating an operation. + * @param op The operation that has been finished. + * @param ca_result The service handle returned from + * GNUNET_TESTBED_ConnectAdapter() (cadet handle). + * @param emsg Error message in case the operation has failed. + * NULL if operation has executed successfully. + */ +static void +cadet_connect_cb (void *cls, + struct GNUNET_TESTBED_Operation *op, + void *ca_result, + const char *emsg) +{ + struct GNUNET_CADET_TEST_Context *ctx = cls; + unsigned int i; + + if (NULL != emsg) + { + fprintf (stderr, "Failed to connect to CADET service: %s\n", + emsg); + GNUNET_SCHEDULER_shutdown (); + return; + } + for (i = 0; i < ctx->num_peers; i++) + if (op == ctx->ops[i]) + { + ctx->cadetes[i] = ca_result; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "...cadet %u connected\n", i); + } + for (i = 0; i < ctx->num_peers; i++) + if (NULL == ctx->cadetes[i]) + return; /* still some CADET connections missing */ + /* all CADET connections ready! */ + ctx->app_main (ctx->app_main_cls, + ctx, + ctx->num_peers, + ctx->peers, + ctx->cadetes); +} + + +void +GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx) +{ + unsigned int i; + + for (i = 0; i < ctx->num_peers; i++) + { + GNUNET_assert (NULL != ctx->ops[i]); + GNUNET_TESTBED_operation_done (ctx->ops[i]); + ctx->ops[i] = NULL; + } + GNUNET_free (ctx->ops); + GNUNET_free (ctx->cadetes); + GNUNET_free (ctx); + GNUNET_SCHEDULER_shutdown (); +} + + +/** + * Callback run when the testbed is ready (peers running and connected to + * each other) + * + * @param cls Closure (context). + * @param h the run handle + * @param num_peers Number of peers that are running. + * @param peers Handles to each one of the @c num_peers peers. + * @param links_succeeded the number of overlay link connection attempts that + * succeeded + * @param links_failed the number of overlay link connection attempts that + * failed + */ +static void +cadet_test_run (void *cls, + struct GNUNET_TESTBED_RunHandle *h, + unsigned int num_peers, + struct GNUNET_TESTBED_Peer **peers, + unsigned int links_succeeded, + unsigned int links_failed) +{ + struct GNUNET_CADET_TEST_Context *ctx = cls; + unsigned int i; + + if (num_peers != ctx->num_peers) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers started %u/%u, ending\n", + num_peers, ctx->num_peers); + exit (1); + } + ctx->peers = peers; + for (i = 0; i < num_peers; i++) + { + struct GNUNET_CADET_TEST_AdapterContext *newctx; + newctx = GNUNET_new (struct GNUNET_CADET_TEST_AdapterContext); + newctx->peer = i; + newctx->ctx = ctx; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting to cadet %u\n", i); + ctx->ops[i] = GNUNET_TESTBED_service_connect (ctx, + peers[i], + "cadet", + &cadet_connect_cb, + ctx, + &cadet_connect_adapter, + &cadet_disconnect_adapter, + newctx); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "op handle %p\n", ctx->ops[i]); + } +} + + +void +GNUNET_CADET_TEST_run (const char *testname, + const char *cfgname, + unsigned int num_peers, + GNUNET_CADET_TEST_AppMain tmain, + void *tmain_cls, + GNUNET_CADET_InboundChannelNotificationHandler new_channel, + GNUNET_CADET_ChannelEndHandler cleaner, + struct GNUNET_CADET_MessageHandler* handlers, + const uint32_t *ports) +{ + struct GNUNET_CADET_TEST_Context *ctx; + + ctx = GNUNET_new (struct GNUNET_CADET_TEST_Context); + ctx->num_peers = num_peers; + ctx->ops = GNUNET_malloc (num_peers * sizeof (struct GNUNET_TESTBED_Operation *)); + ctx->cadetes = GNUNET_malloc (num_peers * sizeof (struct GNUNET_CADET_Handle *)); + ctx->app_main = tmain; + ctx->app_main_cls = tmain_cls; + ctx->new_channel = new_channel; + ctx->cleaner = cleaner; + ctx->handlers = handlers; + ctx->ports = ports; + GNUNET_TESTBED_test_run (testname, + cfgname, + num_peers, + 0LL, NULL, NULL, + &cadet_test_run, ctx); +} + +/* end of cadet_test_lib.c */ diff --git a/src/cadet/cadet_test_lib.h b/src/cadet/cadet_test_lib.h new file mode 100644 index 000000000..f2ed426b0 --- /dev/null +++ b/src/cadet/cadet_test_lib.h @@ -0,0 +1,106 @@ +/* + This file is part of GNUnet. + (C) 2012 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 cadet/cadet_test_lib.h + * @author Bartlomiej Polot + * @brief library for writing CADET tests + */ +#ifndef CADET_TEST_LIB_H +#define CADET_TEST_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_testbed_service.h" +#include "gnunet_cadet_service.h" + +/** + * Test context for a CADET Test. + */ +struct GNUNET_CADET_TEST_Context; + + +/** + * Main function of a CADET test. + * + * @param cls Closure. + * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end. + * @param num_peers Number of peers that are running. + * @param peers Array of peers. + * @param cadetes Handle to each of the CADETs of the peers. + */ +typedef void (*GNUNET_CADET_TEST_AppMain) (void *cls, + struct GNUNET_CADET_TEST_Context *ctx, + unsigned int num_peers, + struct GNUNET_TESTBED_Peer **peers, + struct GNUNET_CADET_Handle **cadetes); + + +/** + * Run a test using the given name, configuration file and number of + * peers. + * All cadet callbacks will receive the peer number as the closure. + * + * @param testname Name of the test (for logging). + * @param cfgname Name of the configuration file. + * @param num_peers Number of peers to start. + * @param tmain Main function to run once the testbed is ready. + * @param tmain_cls Closure for 'tmain'. + * @param new_channel Handler for incoming tunnels. + * @param cleaner Cleaner for destroyed incoming tunnels. + * @param handlers Message handlers. + * @param ports Ports the peers offer. + */ +void +GNUNET_CADET_TEST_run (const char *testname, + const char *cfgname, + unsigned int num_peers, + GNUNET_CADET_TEST_AppMain tmain, + void *tmain_cls, + GNUNET_CADET_InboundChannelNotificationHandler new_channel, + GNUNET_CADET_ChannelEndHandler cleaner, + struct GNUNET_CADET_MessageHandler* handlers, + const uint32_t* ports); + + +/** + * Clean up the testbed. + * + * @param ctx handle for the testbed + */ +void +GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + + +/* ifndef CADET_TEST_LIB_H */ +#endif diff --git a/src/cadet/cadet_tunnel_tree.c b/src/cadet/cadet_tunnel_tree.c new file mode 100644 index 000000000..dd3f3dae1 --- /dev/null +++ b/src/cadet/cadet_tunnel_tree.c @@ -0,0 +1,1174 @@ +/* + This file is part of GNUnet. + (C) 2001 - 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 cadet/cadet_tunnel_tree.c + * @brief Tunnel tree handling functions + * @author Bartlomiej Polot + */ + +#include "cadet.h" +#include "cadet_tunnel_tree.h" + +#define CADET_TREE_DEBUG GNUNET_YES + + +/** + * Node of path tree for a tunnel + */ +struct CadetTunnelTreeNode +{ + /** + * Peer this node describes + */ + GNUNET_PEER_Id peer; + + /** + * Parent node in the tree + */ + struct CadetTunnelTreeNode *parent; + + /** + * DLL of siblings + */ + struct CadetTunnelTreeNode *next; + + /** + * DLL of siblings + */ + struct CadetTunnelTreeNode *prev; + + /** + * DLL of children + */ + struct CadetTunnelTreeNode *children_head; + + /** + * DLL of children + */ + struct CadetTunnelTreeNode *children_tail; + + /** + * Status of the peer in the tunnel + */ + enum CadetPeerState status; +}; + + +/** + * Tree to reach all peers in the tunnel + */ +struct CadetTunnelTree +{ + /** + * Root node of peer tree + */ + struct CadetTunnelTreeNode *root; + + /** + * Node that represents our position in the tree (for non local tunnels) + */ + struct CadetTunnelTreeNode *me; + + /** + * DLL of disconneted nodes + */ + struct CadetTunnelTreeNode *disconnected_head; + + /** + * DLL of disconneted nodes + */ + struct CadetTunnelTreeNode *disconnected_tail; + + /** + * Cache of all peers and the first hop to them. + * Indexed by PeerIdentity, contains a pointer to the PeerIdentity + * of 1st hop. + */ + struct GNUNET_CONTAINER_MultiHashMap *first_hops; + +}; + + +/** + * Create a new path + * + * @param length How many hops will the path have. + * + * @return A newly allocated path with a peer array of the specified length. + */ +struct CadetPeerPath * +path_new (unsigned int length) +{ + struct CadetPeerPath *p; + + p = GNUNET_new (struct CadetPeerPath); + if (length > 0) + { + p->length = length; + p->peers = GNUNET_malloc (length * sizeof (GNUNET_PEER_Id)); + } + return p; +} + + +/** + * Invert the path + * + * @param path the path to invert + */ +void +path_invert (struct CadetPeerPath *path) +{ + GNUNET_PEER_Id aux; + unsigned int i; + + for (i = 0; i < path->length / 2; i++) + { + aux = path->peers[i]; + path->peers[i] = path->peers[path->length - i - 1]; + path->peers[path->length - i - 1] = aux; + } +} + + +/** + * Duplicate a path, incrementing short peer's rc. + * + * @param path The path to duplicate. + */ +struct CadetPeerPath * +path_duplicate (struct CadetPeerPath *path) +{ + struct CadetPeerPath *aux; + unsigned int i; + + aux = path_new (path->length); + memcpy (aux->peers, path->peers, path->length * sizeof (GNUNET_PEER_Id)); + for (i = 0; i < path->length; i++) + GNUNET_PEER_change_rc (path->peers[i], 1); + return aux; +} + + +/** + * Recusively update the info about what is the first hop to reach the node + * + * @param tree Tree this nodes belongs to. + * @param parent The node form which to start updating. + * @param hop If known, ID of the first hop. + * If not known, NULL to find out and pass on children. + */ +static void +tree_node_update_first_hops (struct CadetTunnelTree *tree, + struct CadetTunnelTreeNode *parent, + struct GNUNET_PeerIdentity *hop); + + +/** + * Get the length of a path. + * + * @param path The path to measure, with the local peer at any point of it. + * + * @return Number of hops to reach destination. + * UINT_MAX in case the peer is not in the path. + */ +unsigned int +path_get_length (struct CadetPeerPath *path) +{ + if (NULL == path) + return UINT_MAX; + return path->length; +} + + +/** + * Destroy the path and free any allocated resources linked to it + * + * @param p the path to destroy + * + * @return GNUNET_OK on success + */ +int +path_destroy (struct CadetPeerPath *p) +{ + if (NULL == p) + return GNUNET_OK; + GNUNET_PEER_decrement_rcs (p->peers, p->length); + GNUNET_free_non_null (p->peers); + GNUNET_free (p); + return GNUNET_OK; +} + + + +/** + * Allocates and initializes a new node. + * Sets ID and parent of the new node and inserts it in the DLL of the parent + * + * @param parent Node that will be the parent from the new node, NULL for root + * @param peer Short Id of the new node + * + * @return Newly allocated node + */ +static struct CadetTunnelTreeNode * +tree_node_new (struct CadetTunnelTreeNode *parent, GNUNET_PEER_Id peer) +{ + struct CadetTunnelTreeNode *node; + + node = GNUNET_new (struct CadetTunnelTreeNode); + node->peer = peer; + GNUNET_PEER_change_rc (peer, 1); + node->parent = parent; + if (NULL != parent) + GNUNET_CONTAINER_DLL_insert (parent->children_head, parent->children_tail, + node); + + return node; +} + + +/** + * Recursively find the given peer. + * + * @param parent Node where to start looking. + * @param peer_id Short ID of the peer to find. + * + * @return Pointer to the node of the peer. NULL if not found. + */ +static struct CadetTunnelTreeNode * +tree_node_find_peer (struct CadetTunnelTreeNode *parent, GNUNET_PEER_Id peer_id) +{ + struct CadetTunnelTreeNode *n; + struct CadetTunnelTreeNode *r; + + if (parent->peer == peer_id) + return parent; + for (n = parent->children_head; NULL != n; n = n->next) + { + r = tree_node_find_peer (n, peer_id); + if (NULL != r) + return r; + } + return NULL; +} + + +/** + * Recusively update the info about what is the first hop to reach the node + * + * @param tree Tree this nodes belongs to. + * @param parent ID from node form which to start updating. + * @param hop If known, ID of the first hop. + * If not known, NULL to find out and pass on children. + */ +static void +tree_node_update_first_hops (struct CadetTunnelTree *tree, + struct CadetTunnelTreeNode *parent, + struct GNUNET_PeerIdentity *hop) +{ + struct GNUNET_PeerIdentity pi; + struct GNUNET_PeerIdentity *copy; + struct GNUNET_PeerIdentity id; + struct CadetTunnelTreeNode *n; + +#if CADET_TREE_DEBUG + GNUNET_PEER_resolve (parent->peer, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Finding first hop for %s.\n", + GNUNET_i2s (&id)); +#endif + if (NULL == hop) + { + struct CadetTunnelTreeNode *aux; + struct CadetTunnelTreeNode *old; + + aux = old = parent; + while (aux != tree->me) + { +#if CADET_TREE_DEBUG + GNUNET_PEER_resolve (aux->peer, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: ... checking %s.\n", + GNUNET_i2s (&id)); +#endif + old = aux; + aux = aux->parent; + GNUNET_assert (NULL != aux); + } +#if CADET_TREE_DEBUG + GNUNET_PEER_resolve (old->peer, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: It's %s!\n", + GNUNET_i2s (&id)); +#endif + hop = π + GNUNET_PEER_resolve (old->peer, hop); + } + GNUNET_PEER_resolve (parent->peer, &id); + copy = GNUNET_CONTAINER_multihashmap_get (tree->first_hops, &id.hashPubKey); + if (NULL == copy) + copy = GNUNET_new (struct GNUNET_PeerIdentity); + *copy = *hop; + + (void) GNUNET_CONTAINER_multihashmap_put (tree->first_hops, &id.hashPubKey, + copy, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); + + for (n = parent->children_head; NULL != n; n = n->next) + { + tree_node_update_first_hops (tree, n, hop); + } +} + + +static void +tree_node_debug (struct CadetTunnelTreeNode *n, uint16_t level) +{ + struct CadetTunnelTreeNode *c; + struct GNUNET_PeerIdentity id;; + uint16_t i; + + for (i = 0; i < level; i++) + FPRINTF (stderr, "%s", " "); + if (n->status == CADET_PEER_READY) + FPRINTF (stderr, "%s", "#"); + if (n->status == CADET_PEER_SEARCHING) + FPRINTF (stderr, "%s", "+"); + if (n->status == CADET_PEER_RELAY) + FPRINTF (stderr, "%s", "-"); + if (n->status == CADET_PEER_RECONNECTING) + FPRINTF (stderr, "%s", "*"); + + GNUNET_PEER_resolve (n->peer, &id); + FPRINTF (stderr, "%s, [%u, %p] ", GNUNET_i2s (&id), n->peer, n); + if (NULL != n->parent) + { + GNUNET_PEER_resolve (n->parent->peer, &id); + FPRINTF (stderr, "(-> %s [%u])\n", GNUNET_i2s (&id), n->parent->peer); + } + else + FPRINTF (stderr, "%s", "(root)\n"); + for (c = n->children_head; NULL != c; c = c->next) + tree_node_debug (c, level + 1); +} + + +/** + * Destroys and frees the node and all children + * + * @param parent Parent node to be destroyed + */ +static void +tree_node_destroy (struct CadetTunnelTreeNode *parent) +{ + struct CadetTunnelTreeNode *n; + struct CadetTunnelTreeNode *next; + + if (NULL == parent) + return; +#if CADET_TREE_DEBUG + struct GNUNET_PeerIdentity id; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Destroying node %u\n", + parent->peer); + GNUNET_PEER_resolve (parent->peer, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: (%s)\n", GNUNET_i2s (&id)); +#endif + n = parent->children_head; + while (NULL != n) + { + next = n->next; + tree_node_destroy (n); + n = next; + } + GNUNET_PEER_change_rc (parent->peer, -1); + if (NULL != parent->parent) + GNUNET_CONTAINER_DLL_remove (parent->parent->children_head, + parent->parent->children_tail, parent); + GNUNET_free (parent); +} + + + +/** + * Create a new tree. + * + * @param peer A short peer id of the root of the tree. + * + * @return A newly allocated and initialized tunnel tree. + */ +struct CadetTunnelTree * +tree_new (GNUNET_PEER_Id peer) +{ + struct CadetTunnelTree *tree; + + tree = GNUNET_new (struct CadetTunnelTree); + tree->first_hops = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO); + tree->root = tree_node_new (NULL, peer); + tree->root->status = CADET_PEER_ROOT; + + if (1 == peer) + { + tree->me = tree->root; + } + + return tree; +} + + +/** + * Set the status of a node. + * + * @param tree Tree. + * @param peer A short peer id of the node. + * @param status New status to set. + */ +void +tree_set_status (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer, + enum CadetPeerState status) +{ + struct CadetTunnelTreeNode *n; + + n = tree_find_peer (tree, peer); + if (NULL == n) + return; + n->status = status; +} + + +/** + * Get the status of a node. + * + * @param tree Tree whose node's status we want to now. + * @param peer A short peer id of the node. + * + * @return Status of the peer. + */ +enum CadetPeerState +tree_get_status (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer) +{ + struct CadetTunnelTreeNode *n; + + n = tree_find_peer (tree, peer); + if (NULL == n) + return CADET_PEER_INVALID; + return n->status; +} + + +/** + * Get the id of the predecessor of the local node. + * + * @param tree Tree whose local id we want to now. + * + * @return Short peer id of local peer. + */ +GNUNET_PEER_Id +tree_get_predecessor (struct CadetTunnelTree *tree) +{ + if (NULL != tree->me && NULL != tree->me->parent) + return tree->me->parent->peer; + else + return (GNUNET_PEER_Id) 0; +} + + +/** + * Find the first peer whom to send a packet to go down this path + * + * @param t The tunnel tree to use + * @param peer The peerinfo of the peer we are trying to reach + * + * @return peerinfo of the peer who is the first hop in the tunnel + * NULL on error + * + * FIXME use PEER_Id + */ +struct GNUNET_PeerIdentity * +tree_get_first_hop (struct CadetTunnelTree *t, GNUNET_PEER_Id peer) +{ + struct GNUNET_PeerIdentity id; + struct GNUNET_PeerIdentity *r; + + GNUNET_PEER_resolve (peer, &id); + r = GNUNET_CONTAINER_multihashmap_get (t->first_hops, &id.hashPubKey); + if (NULL == r) + { + struct CadetTunnelTreeNode *n; + + n = tree_find_peer (t, peer); + if (NULL != t->me && NULL != n) + { + tree_node_update_first_hops (t, n, NULL); + r = GNUNET_CONTAINER_multihashmap_get (t->first_hops, &id.hashPubKey); + GNUNET_assert (NULL != r); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Tree structure inconsistent! me: %p, n: %p", t->me, n); + GNUNET_break (0); + } + } + + return r; +} + + +/** + * Find the given peer in the tree. + * + * @param tree Tree where to look for the peer. + * @param peer_id Short ID of the peer to find. + * + * @return Pointer to the node of the peer. NULL if not found. + */ +struct CadetTunnelTreeNode * +tree_find_peer (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer_id) +{ + return tree_node_find_peer (tree->root, peer_id); +} + + +/** + * Recusively mark peer and children as disconnected, notify client + * + * @param tree Tree this node belongs to + * @param parent Node to be clean, potentially with children + * @param cb Callback to use to notify about disconnected peers. + * @param cbcls Closure for cb. + */ +static void +tree_mark_peers_disconnected (struct CadetTunnelTree *tree, + struct CadetTunnelTreeNode *parent, + CadetTreeCallback cb, void *cbcls) +{ + struct GNUNET_PeerIdentity *pi; + struct GNUNET_PeerIdentity id; + struct CadetTunnelTreeNode *n; + + for (n = parent->children_head; NULL != n; n = n->next) + { + tree_mark_peers_disconnected (tree, n, cb, cbcls); + } + if (CADET_PEER_READY == parent->status) + { + if (NULL != cb) + cb (cbcls, parent->peer); + parent->status = CADET_PEER_RECONNECTING; + } + + /* Remove and free info about first hop */ + GNUNET_PEER_resolve (parent->peer, &id); + pi = GNUNET_CONTAINER_multihashmap_get (tree->first_hops, &id.hashPubKey); + GNUNET_CONTAINER_multihashmap_remove_all (tree->first_hops, &id.hashPubKey); + if (NULL != pi) + GNUNET_free (pi); +} + + +/** + * Iterate over all children of the local node. + * + * @param tree Tree to use. Must have "me" set. + * @param cb Callback to call over each child. + * @param cb_cls Closure for @c cb. + */ +void +tree_iterate_children (struct CadetTunnelTree *tree, CadetTreeCallback cb, + void *cb_cls) +{ + struct CadetTunnelTreeNode *n; + + if (NULL == tree->me) + return; + for (n = tree->me->children_head; NULL != n; n = n->next) + { + cb (cb_cls, n->peer); + } +} + + +/** + * Struct to contain a list of pending nodes when iterating a tree. + */ +struct CadetTreePendingNode { + + /** + * DLL next. + */ + struct CadetTreePendingNode *next; + + /** + * DLL prev. + */ + struct CadetTreePendingNode *prev; + + /** + * Pending node. + */ + struct CadetTunnelTreeNode *node; +}; + + +/** + * Iterate over all nodes in the tree. + * + * @param tree Tree to use.. + * @param cb Callback to call over each child. + * @param cb_cls Closure for @c cb. + * + * TODO: recursive implementation? (s/heap/stack/g) + */ +void +tree_iterate_all (struct CadetTunnelTree *tree, + CadetWholeTreeCallback cb, + void *cb_cls) +{ + struct CadetTunnelTreeNode *parent; + struct CadetTunnelTreeNode *n; + struct CadetTreePendingNode *head; + struct CadetTreePendingNode *tail; + struct CadetTreePendingNode *pending; + + cb (cb_cls, tree->root->peer, 0); + pending = GNUNET_new (struct CadetTreePendingNode); + pending->node = tree->root; + head = tail = NULL; + GNUNET_CONTAINER_DLL_insert (head, tail, pending); + + while (NULL != head) + { + pending = head; + parent = pending->node; + GNUNET_CONTAINER_DLL_remove (head, tail, pending); + GNUNET_free (pending); + for (n = parent->children_head; NULL != n; n = n->next) + { + cb (cb_cls, n->peer, parent->peer); + pending = GNUNET_new (struct CadetTreePendingNode); + pending->node = n; + /* Insert_tail: breadth first, Insert: depth first */ + GNUNET_CONTAINER_DLL_insert (head, tail, pending); + } + } +} + + +/** + * Iterator to count the children in a tree. + */ +static void +count_children_cb (void *cls, GNUNET_PEER_Id peer) +{ + unsigned int *i = cls; + + (*i)++; +} + + +/** + * Count how many children does the local node have in the tree. + * + * @param tree Tree to use. Must have "me" set. + */ +unsigned int +tree_count_children (struct CadetTunnelTree *tree) +{ + unsigned int i; + + i = 0; + tree_iterate_children(tree, &count_children_cb, &i); + return i; +} + + +/** + * Recusively update the info about what is the first hop to reach the node + * + * @param tree Tree this nodes belongs to. + * @param parent_id Short ID from node form which to start updating. + * @param hop If known, ID of the first hop. + * If not known, NULL to find out and pass on children. + */ +void +tree_update_first_hops (struct CadetTunnelTree *tree, GNUNET_PEER_Id parent_id, + struct GNUNET_PeerIdentity *hop) +{ + tree_node_update_first_hops (tree, tree_find_peer (tree, parent_id), hop); +} + + +/** + * Delete the current path to the peer, including all now unused relays. + * The destination peer is NOT destroyed, it is returned in order to either set + * a new path to it or destroy it explicitly, taking care of it's child nodes. + * + * @param t Tunnel tree where to delete the path from. + * @param peer_id Short ID of the destination peer whose path we want to remove. + * @param cb Callback to use to notify about disconnected peers. + * @param cbcls Closure for cb. + * + * @return pointer to the pathless node. + * NULL when not found + */ +struct CadetTunnelTreeNode * +tree_del_path (struct CadetTunnelTree *t, GNUNET_PEER_Id peer_id, + CadetTreeCallback cb, void *cbcls) +{ + struct CadetTunnelTreeNode *parent; + struct CadetTunnelTreeNode *node; + struct CadetTunnelTreeNode *n; + +#if CADET_TREE_DEBUG + struct GNUNET_PeerIdentity id; + + GNUNET_PEER_resolve (peer_id, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Deleting path to %s.\n", + GNUNET_i2s (&id)); +#endif + if (NULL == t->root || peer_id == t->root->peer) + return NULL; + + for (n = t->disconnected_head; NULL != n; n = n->next) + { + if (n->peer == peer_id) + { + /* Was already pathless, waiting for reconnection */ + GNUNET_CONTAINER_DLL_remove (t->disconnected_head, t->disconnected_tail, + n); + return n; + } + } + n = tree_find_peer (t, peer_id); + if (NULL == n) + return NULL; + node = n; + + parent = n->parent; + GNUNET_CONTAINER_DLL_remove (parent->children_head, parent->children_tail, n); + n->parent = NULL; + + while (CADET_PEER_RELAY == parent->status && + NULL == parent->children_head) + { +#if CADET_TREE_DEBUG + GNUNET_PEER_resolve (parent->peer, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Deleting node %s.\n", + GNUNET_i2s (&id)); +#endif + n = parent->parent; + if (parent == t->me) + t->me = NULL; + tree_node_destroy (parent); + parent = n; + } +#if CADET_TREE_DEBUG + GNUNET_PEER_resolve (parent->peer, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Not deleted peer %s.\n", + GNUNET_i2s (&id)); +#endif + + tree_mark_peers_disconnected (t, node, cb, cbcls); + + return node; +} + + +/** + * Return a newly allocated individual path to reach a peer from the local peer, + * according to the path tree of some tunnel. + * + * @param t Tunnel from which to read the path tree. + * @param peer Short ID of the destination peer to whom we want a path. + * + * @return A newly allocated individual path to reach the destination peer. + * Path must be destroyed afterwards. + */ +struct CadetPeerPath * +tree_get_path_to_peer (struct CadetTunnelTree *t, GNUNET_PEER_Id peer) +{ + struct CadetTunnelTreeNode *n; + struct CadetPeerPath *p; + + n = tree_find_peer (t, peer); + if (NULL == n) + { + GNUNET_break (0); + return NULL; + } + p = path_new (0); + + /* Building the path (inverted!) */ + while (n->peer != 1) + { + GNUNET_array_append (p->peers, p->length, n->peer); + GNUNET_PEER_change_rc (n->peer, 1); + n = n->parent; + if (NULL == n) + { + GNUNET_break (0); + path_destroy (p); + return NULL; + } + } + GNUNET_array_append (p->peers, p->length, 1); + GNUNET_PEER_change_rc (1, 1); + + path_invert (p); + + return p; +} + + + +/** + * Integrate a stand alone path into the tunnel tree. + * If the peer toward which the new path is already in the tree, the peer + * and its children will be maked as disconnected and the callback + * will be called on each one of them. They will be maked as online only after + * receiving a PATH ACK for the new path for each one of them, so the caller + * should take care of sending a new CREATE PATH message for each disconnected + * peer. + * + * @param t Tunnel where to add the new path. + * @param p Path to be integrated. + * @param cb Callback to use to notify about peers temporarily disconnecting. + * @param cbcls Closure for cb. + * + * @return GNUNET_OK in case of success. + * GNUNET_SYSERR in case of error. + * + * TODO: optimize + * - go backwards on path looking for each peer in the present tree + * - do not disconnect peers until new path is created & connected + */ +int +tree_add_path (struct CadetTunnelTree *t, const struct CadetPeerPath *p, + CadetTreeCallback cb, void *cbcls) +{ + struct CadetTunnelTreeNode *parent; + struct CadetTunnelTreeNode *oldnode; + struct CadetTunnelTreeNode *n; + struct CadetTunnelTreeNode *c; + struct GNUNET_PeerIdentity id; + int me; + unsigned int i; + +#if CADET_TREE_DEBUG + GNUNET_PEER_resolve (p->peers[p->length - 1], &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "tree: Adding path [%u] towards peer %s.\n", p->length, + GNUNET_i2s (&id)); +#endif + + GNUNET_assert (0 != p->length); + parent = n = t->root; + if (n->peer != p->peers[0]) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (1 == p->length) + return GNUNET_OK; + oldnode = tree_del_path (t, p->peers[p->length - 1], cb, cbcls); + /* Look for the first node that is not already present in the tree + * + * Assuming that the tree is somewhat balanced, O(log n * log N). + * - Length of the path is expected to be log N (size of whole network). + * - Each level of the tree is expected to have log n children (size of tree). + */ + me = t->root->peer == 1 ? 0 : -1; + for (i = 1; i < p->length; i++) + { +#if CADET_TREE_DEBUG + GNUNET_PEER_resolve (p->peers[i], &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Looking for peer %s.\n", + GNUNET_i2s (&id)); +#endif + parent = n; + if (p->peers[i] == 1) + me = i; + for (c = n->children_head; NULL != c; c = c->next) + { + if (c->peer == p->peers[i]) + { +#if CADET_TREE_DEBUG + GNUNET_PEER_resolve (parent->peer, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "tree: Found in children of %s.\n", GNUNET_i2s (&id)); +#endif + n = c; + break; + } + } + /* If we couldn't find a child equal to path[i], we have reached the end + * of the common path. */ + if (parent == n) + break; + } +#if CADET_TREE_DEBUG + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: All childen visited.\n"); +#endif + /* Add the rest of the path as a branch from parent. */ + while (i < p->length) + { +#if CADET_TREE_DEBUG + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Adding peer %u to %u.\n", + p->peers[i], parent->peer); + GNUNET_PEER_resolve (p->peers[i], &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Adding peer %s.\n", + GNUNET_i2s (&id)); + GNUNET_PEER_resolve (parent->peer, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: to %s.\n", + GNUNET_i2s (&id)); +#endif + + if (i == p->length - 1 && NULL != oldnode) + { +#if CADET_TREE_DEBUG + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "tree: Putting old node into place.\n"); +#endif + oldnode->parent = parent; + GNUNET_CONTAINER_DLL_insert (parent->children_head, parent->children_tail, + oldnode); + tree_node_update_first_hops (t, oldnode, NULL); + n = oldnode; + } + else + { +#if CADET_TREE_DEBUG + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Creating new node.\n"); +#endif + n = tree_node_new (parent, p->peers[i]); + n->status = CADET_PEER_RELAY; + } + if (n->peer == 1) + { + t->me = n; + me = i; + } + i++; + parent = n; + } + n->status = CADET_PEER_SEARCHING; + + GNUNET_break (-1 != me); + + /* Add info about first hop into hashmap. */ + if (-1 != me && me < p->length - 1) + { +#if CADET_TREE_DEBUG + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "CADET: finding first hop (own pos %d/%u)\n", me, + p->length - 1); +#endif + GNUNET_PEER_resolve (p->peers[me + 1], &id); + tree_update_first_hops (t, p->peers[me + 1], &id); + } +#if CADET_TREE_DEBUG + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "CADET: was last in path, not updating first hops (%d/%u)\n", + me, p->length - 1); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: New node added.\n"); +#endif + if (NULL == t->me) + t->me = tree_find_peer (t, 1); + return GNUNET_OK; +} + + +/** + * Notifies a tree that a connection it might be using is broken. + * Marks all peers down the paths as disconnected and notifies the client. + * + * @param t Tree to use. + * @param p1 Short id of one of the peers (order unimportant) + * @param p2 Short id of one of the peers (order unimportant) + * @param cb Function to call for every peer that is marked as disconnected. + * @param cbcls Closure for cb. + * + * @return Short ID of the first disconnected peer in the tree. + */ +GNUNET_PEER_Id +tree_notify_connection_broken (struct CadetTunnelTree *t, GNUNET_PEER_Id p1, + GNUNET_PEER_Id p2, CadetTreeCallback cb, + void *cbcls) +{ + struct CadetTunnelTreeNode *n; + struct CadetTunnelTreeNode *c; + + n = tree_find_peer (t, p1); + if (NULL == n) + return 0; + if (NULL != n->parent && n->parent->peer == p2) + { + tree_mark_peers_disconnected (t, n, cb, cbcls); + GNUNET_CONTAINER_DLL_remove (n->parent->children_head, + n->parent->children_tail, n); + GNUNET_CONTAINER_DLL_insert (t->disconnected_head, t->disconnected_tail, n); + return p1; + } + for (c = n->children_head; NULL != c; c = c->next) + { + if (c->peer == p2) + { + tree_mark_peers_disconnected (t, c, cb, cbcls); + GNUNET_CONTAINER_DLL_remove (n->children_head, n->children_tail, c); + GNUNET_CONTAINER_DLL_insert (t->disconnected_head, t->disconnected_tail, + c); + return p2; + } + } + return 0; +} + + +/** + * Deletes a peer from a tunnel, liberating all unused resources on the path to + * it. It shouldn't have children, if it has they will be destroyed as well. + * If the tree is not local and no longer has any paths, the root node will be + * destroyed and marked as NULL. + * + * @param t Tunnel tree to use. + * @param peer Short ID of the peer to remove from the tunnel tree. + * @param cb Callback to notify client of disconnected peers. + * @param cbcls Closure for cb. + * + * @return GNUNET_OK or GNUNET_SYSERR + */ +int +tree_del_peer (struct CadetTunnelTree *t, GNUNET_PEER_Id peer, + CadetTreeCallback cb, void *cbcls) +{ + struct CadetTunnelTreeNode *n; + + n = tree_del_path (t, peer, cb, cbcls); + if (NULL == n) + { + GNUNET_break (0); + return GNUNET_YES; + } + tree_node_destroy (n); + if (NULL == t->root->children_head && t->me != t->root) + { + tree_node_destroy (t->root); + t->root = NULL; + return GNUNET_NO; + } + return GNUNET_YES; +} + + + +/** + * Get the cost of the path relative to the already built tunnel tree. + * + * @param t The tunnel tree to which compare. + * @param path The individual path to reach a peer. It has to start at the + * root of the tree to be comparable. + * + * @return Number of hops to reach destination, UINT_MAX in case the peer is not + * in the path. + * + * TODO: adapt to allow any start / root combination + * TODO: take in account state of the nodes + */ +unsigned int +tree_get_path_cost (struct CadetTunnelTree *t, struct CadetPeerPath *path) +{ + struct CadetTunnelTreeNode *n; + struct CadetTunnelTreeNode *p; + unsigned int i; + unsigned int l; + + l = path_get_length (path); + p = t->root; + if (t->root->peer != path->peers[0]) + { + GNUNET_break (0); + return UINT_MAX; + } + for (i = 1; i < l; i++) + { + for (n = p->children_head; NULL != n; n = n->next) + { + if (path->peers[i] == n->peer) + { + break; + } + } + if (NULL == n) + return l - i; + p = n; + } + return l - i; +} + + +/** + * Print the tree on stderr + * + * @param t The tree + */ +void +tree_debug (struct CadetTunnelTree *t) +{ + tree_node_debug (t->root, 0); + FPRINTF (stderr, "root: %p\n", t->root); + FPRINTF (stderr, "me: %p\n", t->me); +} + + +/** + * Iterator over hash map peer entries and frees all data in it. + * Used prior to destroying a hashmap. Makes you miss anonymous functions in C. + * + * @param cls closure + * @param key current key code (will no longer contain valid data!!) + * @param value value in the hash map (treated as void *) + * @return GNUNET_YES if we should continue to iterate, GNUNET_NO if not. + */ +static int +iterate_free (void *cls, const struct GNUNET_HashCode * key, void *value) +{ + GNUNET_free (value); + return GNUNET_YES; +} + + +/** + * Destroy the whole tree and free all used memory and Peer_Ids + * + * @param t Tree to be destroyed + */ +void +tree_destroy (struct CadetTunnelTree *t) +{ +#if CADET_TREE_DEBUG + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Destroying tree\n"); +#endif + tree_node_destroy (t->root); + GNUNET_CONTAINER_multihashmap_iterate (t->first_hops, &iterate_free, NULL); + GNUNET_CONTAINER_multihashmap_destroy (t->first_hops); + GNUNET_free (t); +} diff --git a/src/cadet/cadet_tunnel_tree.h b/src/cadet/cadet_tunnel_tree.h new file mode 100644 index 000000000..779d330e7 --- /dev/null +++ b/src/cadet/cadet_tunnel_tree.h @@ -0,0 +1,382 @@ +/* + This file is part of GNUnet. + (C) 2001 - 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 cadet/cadet_tunnel_tree.h + * @brief Tunnel tree handling functions + * @author Bartlomiej Polot + */ + +#include "cadet.h" + +/******************************************************************************/ +/************************ DATA STRUCTURES ****************************/ +/******************************************************************************/ + +/** + * Information regarding a possible path to reach a single peer + */ +struct CadetPeerPath +{ + + /** + * Linked list + */ + struct CadetPeerPath *next; + struct CadetPeerPath *prev; + + /** + * List of all the peers that form the path from origin to target. + */ + GNUNET_PEER_Id *peers; + + /** + * Number of peers (hops) in the path + */ + unsigned int length; + +}; + + +/** + * Node of path tree for a tunnel + */ +struct CadetTunnelTreeNode; + + +/** + * Tree to reach all peers in the tunnel + */ +struct CadetTunnelTree; + + +/******************************************************************************/ +/************************* FUNCTIONS *****************************/ +/******************************************************************************/ + +/** + * Create a new path. + * + * @param length How many hops will the path have. + * + * @return A newly allocated path with a peer array of the specified length. + */ +struct CadetPeerPath * +path_new (unsigned int length); + + +/** + * Invert the path. + * + * @param path The path to invert. + */ +void +path_invert (struct CadetPeerPath *path); + + +/** + * Duplicate a path, incrementing short peer's rc. + * + * @param path The path to duplicate. + */ +struct CadetPeerPath * +path_duplicate (struct CadetPeerPath *path); + + +/** + * Get the length of a path. + * + * @param path The path to measure, with the local peer at any point of it. + * + * @return Number of hops to reach destination. + * UINT_MAX in case the peer is not in the path. + */ +unsigned int +path_get_length (struct CadetPeerPath *path); + + +/** + * Destroy the path and free any allocated resources linked to it + * + * @param p the path to destroy + * + * @return GNUNET_OK on success + */ +int +path_destroy (struct CadetPeerPath *p); + + +/******************************************************************************/ + +/** + * Iterator over all children of a node. + * + * @param cls Closure. + * @param peer_id Short ID of the peer. + */ +typedef void (*CadetTreeCallback) (void *cls, GNUNET_PEER_Id peer_id); + + +/** + * Iterator over all nodes in a tree. + * + * @param cls Closure. + * @param peer_id Short ID of the peer. + * @param peer_id Short ID of the parent of the peer. + */ +typedef void (*CadetWholeTreeCallback) (void *cls, + GNUNET_PEER_Id peer_id, + GNUNET_PEER_Id parent_id); + +/** + * Create a new tunnel tree associated to a tunnel + * + * @param peer A short peer id of the root of the tree + * + * @return A newly allocated and initialized tunnel tree + */ +struct CadetTunnelTree * +tree_new (GNUNET_PEER_Id peer); + + +/** + * Set the status of a node. + * + * @param tree Tree. + * @param peer A short peer id of the node. + * @param status New status to set. + */ +void +tree_set_status (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer, + enum CadetPeerState status); + + +/** + * Get the status of a node. + * + * @param tree Tree whose local id we want to now. + * @param peer A short peer id of the node. + * + * @return Short peer id of local peer. + */ +enum CadetPeerState +tree_get_status (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer); + + +/** + * Get the id of the predecessor of the local node. + * + * @param tree Tree whose local id we want to now. + * + * @return Short peer id of local peer. + */ +GNUNET_PEER_Id +tree_get_predecessor (struct CadetTunnelTree *tree); + + +/** + * Find the first peer whom to send a packet to go down this path + * + * @param t The tunnel tree to use + * @param peer The peerinfo of the peer we are trying to reach + * + * @return peerinfo of the peer who is the first hop in the tunnel + * NULL on error + */ +struct GNUNET_PeerIdentity * +tree_get_first_hop (struct CadetTunnelTree *t, GNUNET_PEER_Id peer); + + +/** + * Find the given peer in the tree. + * + * @param tree Tree where to look for the peer. + * @param peer_id Peer to find. + * + * @return Pointer to the node of the peer. NULL if not found. + */ +struct CadetTunnelTreeNode * +tree_find_peer (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer_id); + + +/** + * Iterate over all children of the local node. + * + * @param tree Tree to use. Must have "me" set. + * @param cb Callback to call over each child. + * @param cb_cls Closure for @c cb. + */ +void +tree_iterate_children (struct CadetTunnelTree *tree, + CadetTreeCallback cb, + void *cb_cls); + + +/** + * Iterate over all nodes in the tree. + * + * @param tree Tree to use.. + * @param cb Callback to call over each child. + * @param cb_cls Closure for @c cb. + * + * TODO: recursive implementation? (s/heap/stack/g) + */ +void +tree_iterate_all (struct CadetTunnelTree *tree, + CadetWholeTreeCallback cb, + void *cb_cls); + +/** + * Count how many children does the local node have in the tree. + * + * @param tree Tree to use. Must have "me" set. + */ +unsigned int +tree_count_children (struct CadetTunnelTree *tree); + + +/** + * Recusively update the info about what is the first hop to reach the node + * + * @param tree Tree this nodes belongs to. + * @param parent_id Short ID from node form which to start updating. + * @param hop If known, ID of the first hop. + * If not known, NULL to find out and pass on children. + */ +void +tree_update_first_hops (struct CadetTunnelTree *tree, GNUNET_PEER_Id parent_id, + struct GNUNET_PeerIdentity *hop); + +/** + * Delete the current path to the peer, including all now unused relays. + * The destination peer is NOT destroyed, it is returned in order to either set + * a new path to it or destroy it explicitly, taking care of it's child nodes. + * + * @param t Tunnel tree where to delete the path from. + * @param peer_id Short ID of the destination peer whose path we want to remove. + * @param cb Callback to use to notify about which peers are going to be + * disconnected. + * @param cbcls Closure for cb. + * + * @return pointer to the pathless node. + * NULL when not found + */ +struct CadetTunnelTreeNode * +tree_del_path (struct CadetTunnelTree *t, GNUNET_PEER_Id peer_id, + CadetTreeCallback cb, void *cbcls); + + +/** + * Return a newly allocated individual path to reach a peer from the local peer, + * according to the path tree of some tunnel. + * + * @param t Tunnel from which to read the path tree + * @param peer Destination peer to whom we want a path + * + * @return A newly allocated individual path to reach the destination peer. + * Path must be destroyed afterwards. + */ +struct CadetPeerPath * +tree_get_path_to_peer (struct CadetTunnelTree *t, GNUNET_PEER_Id peer); + + +/** + * Integrate a stand alone path into the tunnel tree. + * + * @param t Tunnel where to add the new path. + * @param p Path to be integrated. + * @param cb Callback to use to notify about peers temporarily disconnecting. + * @param cbcls Closure for cb. + * + * @return GNUNET_OK in case of success. + * GNUNET_SYSERR in case of error. + */ +int +tree_add_path (struct CadetTunnelTree *t, const struct CadetPeerPath *p, + CadetTreeCallback cb, void *cbcls); + + +/** + * Notifies a tree that a connection it might be using is broken. + * Marks all peers down the paths as disconnected and notifies the client. + * + * @param t Tree to use. + * @param p1 Short id of one of the peers (order unimportant) + * @param p2 Short id of one of the peers (order unimportant) + * @param cb Function to call for every peer that is marked as disconnected. + * @param cbcls Closure for cb. + * + * @return Short ID of the first disconnected peer in the tree. + */ +GNUNET_PEER_Id +tree_notify_connection_broken (struct CadetTunnelTree *t, GNUNET_PEER_Id p1, + GNUNET_PEER_Id p2, CadetTreeCallback cb, + void *cbcls); + + +/** + * Deletes a peer from a tunnel, liberating all unused resources on the path to + * it. It shouldn't have children, if it has they will be destroyed as well. + * If the tree is not local and no longer has any paths, the root node will be + * destroyed and marked as NULL. + * + * FIXME: dont destroy the root + * + * @param t Tunnel tree to use. + * @param peer Short ID of the peer to remove from the tunnel tree. + * @param cb Callback to notify client of disconnected peers. + * @param cbcls Closure for cb. + * + * @return GNUNET_YES if the tunnel still has nodes + */ +int +tree_del_peer (struct CadetTunnelTree *t, GNUNET_PEER_Id peer, + CadetTreeCallback cb, void *cbcls); + + +/** + * Get the cost of the path relative to the already built tunnel tree + * + * @param t The tunnel tree to which compare + * @param path The individual path to reach a peer + * + * @return Number of hops to reach destination, UINT_MAX in case the peer is not + * in the path + */ +unsigned int +tree_get_path_cost (struct CadetTunnelTree *t, struct CadetPeerPath *path); + + +/** + * Print the tree on stderr + * + * @param t The tree + */ +void +tree_debug (struct CadetTunnelTree *t); + + +/** + * Destroy the whole tree and free all used memory and Peer_Ids + * + * @param t Tree to be destroyed + */ +void +tree_destroy (struct CadetTunnelTree *t); diff --git a/src/cadet/gnunet-cadet-profiler.c b/src/cadet/gnunet-cadet-profiler.c new file mode 100644 index 000000000..c944caa75 --- /dev/null +++ b/src/cadet/gnunet-cadet-profiler.c @@ -0,0 +1,1092 @@ +/* + 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 cadet/gnunet-cadet-profiler.c + * + * @brief Profiler for cadet experiments. + */ +#include +#include "platform.h" +#include "cadet_test_lib.h" +#include "gnunet_cadet_service.h" +#include "gnunet_statistics_service.h" + + +#define PING 1 +#define PONG 2 + + +/** + * Paximum ping period in milliseconds. Real period = rand (0, PING_PERIOD) + */ +#define PING_PERIOD 1000 + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) + +/** + * Time to wait for stuff that should be rather fast + */ +#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +/** + * Total number of rounds. + */ +#define number_rounds sizeof(rounds)/sizeof(rounds[0]) + +/** + * Ratio of peers active. First round always is 1.0. + */ +static float rounds[] = {0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.0}; + +/** + * Message type for pings. + */ +struct CadetPingMessage +{ + /** + * Header. Type PING/PONG. + */ + struct GNUNET_MessageHeader header; + + /** + * Message number. + */ + uint32_t counter; + + /** + * Time the message was sent. + */ + struct GNUNET_TIME_AbsoluteNBO timestamp; + + /** + * Round number. + */ + uint32_t round_number; +}; + +/** + * Peer description. + */ +struct CadetPeer +{ + /** + * Testbed Operation (to get peer id, etc). + */ + struct GNUNET_TESTBED_Operation *op; + + /** + * Peer ID. + */ + struct GNUNET_PeerIdentity id; + + /** + * Cadet handle for the root peer + */ + struct GNUNET_CADET_Handle *cadet; + + /** + * Channel handle for the root peer + */ + struct GNUNET_CADET_Channel *ch; + + /** + * Channel handle for the dest peer + */ + struct GNUNET_CADET_Channel *incoming_ch; + + /** + * Channel handle for a warmup channel. + */ + struct GNUNET_CADET_Channel *warmup_ch; + + /** + * Number of payload packes sent + */ + int data_sent; + + /** + * Number of payload packets received + */ + int data_received; + + /** + * Is peer up? + */ + int up; + + /** + * Destinaton to ping. + */ + struct CadetPeer *dest; + + /** + * Incoming channel for pings. + */ + struct CadetPeer *incoming; + + /** + * Task to do the next ping. + */ + GNUNET_SCHEDULER_TaskIdentifier ping_task; + + float mean[number_rounds]; + float var[number_rounds]; + unsigned int pongs[number_rounds]; + unsigned int pings[number_rounds]; + +}; + +/** + * Duration of each round. + */ +static struct GNUNET_TIME_Relative round_time; + +/** + * GNUNET_PeerIdentity -> CadetPeer + */ +static struct GNUNET_CONTAINER_MultiPeerMap *ids; + +/** + * Testbed peer handles. + */ +static struct GNUNET_TESTBED_Peer **testbed_handles; + +/** + * Testbed Operation (to get stats). + */ +static struct GNUNET_TESTBED_Operation *stats_op; + +/** + * Operation to get peer ids. + */ +struct CadetPeer *peers; + +/** + * Peer ids counter. + */ +static unsigned int p_ids; + +/** + * Total number of peers. + */ +static unsigned long long peers_total; + +/** + * Number of currently running peers. + */ +static unsigned long long peers_running; + +/** + * Number of peers doing pings. + */ +static unsigned long long peers_pinging; + +/** + * Test context (to shut down). + */ +static struct GNUNET_CADET_TEST_Context *test_ctx; + +/** + * Task called to shutdown test. + */ +static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; + +/** + * Task called to disconnect peers, before shutdown. + */ +static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; + +/** + * Task to perform tests + */ +static GNUNET_SCHEDULER_TaskIdentifier test_task; + +/** + * Round number. + */ +static unsigned int current_round; + +/** + * Do preconnect? (Each peer creates a tunnel to one other peer). + */ +static int do_warmup; + +/** + * Warmup progress. + */ +static unsigned int peers_warmup; + +/** + * Flag to notify callbacks not to generate any new traffic anymore. + */ +static int test_finished; + + +/** + * START THE TEST ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES. + * + * Testcase continues when the root receives confirmation of connected peers, + * on callback funtion ch. + * + * @param cls Closure (unsued). + * @param tc Task Context. + */ +static void +start_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Calculate a random delay. + * + * @param max Exclusive maximum, in ms. + * + * @return A time between 0 a max-1 ms. + */ +static struct GNUNET_TIME_Relative +delay_ms_rnd (unsigned int max) +{ + unsigned int rnd; + + rnd = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, max); + return GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, rnd); +} + + +/** + * Get the index of a peer in the peers array. + * + * @param peer Peer whose index to get. + * + * @return Index of peer in peers. + */ +static unsigned int +get_index (struct CadetPeer *peer) +{ + return peer - peers; +} + + +/** + * Show the results of the test (banwidth acheived) and log them to GAUGER + */ +static void +show_end_data (void) +{ + struct CadetPeer *peer; + unsigned int i; + unsigned int j; + + for (i = 0; i < number_rounds; i++) + { + for (j = 0; j < peers_pinging; j++) + { + peer = &peers[j]; + FPRINTF (stdout, + "ROUND %3u PEER %3u: %10.2f / %10.2f, PINGS: %3u, PONGS: %3u\n", + i, j, peer->mean[i], sqrt (peer->var[i] / (peer->pongs[i] - 1)), + peer->pings[i], peer->pongs[i]); + } + } +} + + +/** + * Shut down peergroup, clean up. + * + * @param cls Closure (unused). + * @param tc Task Context. + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Ending test.\n"); + shutdown_handle = GNUNET_SCHEDULER_NO_TASK; +} + + +/** + * Disconnect from cadet services af all peers, call shutdown. + * + * @param cls Closure (unused). + * @param tc Task Context. + */ +static void +disconnect_cadet_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + long line = (long) cls; + unsigned int i; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "disconnecting cadet service, called from line %ld\n", line); + disconnect_task = GNUNET_SCHEDULER_NO_TASK; + for (i = 0; i < peers_total; i++) + { + if (NULL != peers[i].op) + GNUNET_TESTBED_operation_done (peers[i].op); + + if (peers[i].up != GNUNET_YES) + continue; + + if (NULL != peers[i].ch) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u: channel %p\n", i, peers[i].ch); + GNUNET_CADET_channel_destroy (peers[i].ch); + } + if (NULL != peers[i].warmup_ch) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u: warmup channel %p\n", + i, peers[i].warmup_ch); + GNUNET_CADET_channel_destroy (peers[i].warmup_ch); + } + if (NULL != peers[i].incoming_ch) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u: incoming channel %p\n", + i, peers[i].incoming_ch); + GNUNET_CADET_channel_destroy (peers[i].incoming_ch); + } + } + GNUNET_CADET_TEST_cleanup (test_ctx); + if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle) + { + GNUNET_SCHEDULER_cancel (shutdown_handle); + } + shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); +} + + +/** + * Finish test normally: schedule disconnect and shutdown + * + * @param line Line in the code the abort is requested from (__LINE__). + */ +static void +abort_test (long line) +{ + if (disconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, + (void *) line); + } +} + +/** + * Stats callback. Finish the stats testbed operation and when all stats have + * been iterated, shutdown the test. + * + * @param cls closure + * @param op the operation that has been finished + * @param emsg error message in case the operation has failed; will be NULL if + * operation has executed successfully. + */ +static void +stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg) +{ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "... collecting statistics done.\n"); + GNUNET_TESTBED_operation_done (stats_op); + + if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, + (void *) __LINE__); + +} + + +/** + * Process statistic values. + * + * @param cls closure + * @param peer the peer the statistic belong to + * @param subsystem name of subsystem that created the statistic + * @param name the name of the datum + * @param value the current value + * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not + * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + */ +static int +stats_iterator (void *cls, const struct GNUNET_TESTBED_Peer *peer, + const char *subsystem, const char *name, + uint64_t value, int is_persistent) +{ + uint32_t i; + + i = GNUNET_TESTBED_get_index (peer); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " STATS %u - %s [%s]: %llu\n", + i, subsystem, name, value); + + return GNUNET_OK; +} + + +/** + * Task check that keepalives were sent and received. + * + * @param cls Closure (NULL). + * @param tc Task Context. + */ +static void +collect_stats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0) + return; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Start collecting statistics...\n"); + stats_op = GNUNET_TESTBED_get_statistics (peers_total, testbed_handles, + NULL, NULL, + stats_iterator, stats_cont, NULL); +} + + +/** + * @brief Finish profiler normally. Signal finish and start collecting stats. + * + * @param cls Closure (unused). + * @param tc Task context. + */ +static void +finish_profiler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0) + return; + + test_finished = GNUNET_YES; + show_end_data(); + GNUNET_SCHEDULER_add_now (&collect_stats, NULL); +} + +/** + * Set the total number of running peers. + * + * @param target Desired number of running peers. + */ +static void +adjust_running_peers (unsigned int target) +{ + struct GNUNET_TESTBED_Operation *op; + unsigned int delta; + unsigned int run; + unsigned int i; + unsigned int r; + + GNUNET_assert (target <= peers_total); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "adjust peers to %u\n", target); + if (target > peers_running) + { + delta = target - peers_running; + run = GNUNET_YES; + } + else + { + delta = peers_running - target; + run = GNUNET_NO; + } + + for (i = 0; i < delta; i++) + { + do { + r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + peers_total - peers_pinging); + r += peers_pinging; + } while (peers[r].up == run || NULL != peers[r].incoming); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "St%s peer %u: %s\n", + run ? "arting" : "opping", r, GNUNET_i2s (&peers[r].id)); + + if (GNUNET_SCHEDULER_NO_TASK != peers[r].ping_task) + GNUNET_SCHEDULER_cancel (peers[r].ping_task); + peers[r].ping_task = GNUNET_SCHEDULER_NO_TASK; + + peers[r].up = run; + + if (NULL != peers[r].ch) + GNUNET_CADET_channel_destroy (peers[r].ch); + peers[r].ch = NULL; + if (NULL != peers[r].dest) + { + if (NULL != peers[r].dest->incoming_ch) + GNUNET_CADET_channel_destroy (peers[r].dest->incoming_ch); + peers[r].dest->incoming_ch = NULL; + } + + op = GNUNET_TESTBED_peer_manage_service (&peers[r], testbed_handles[r], + "cadet", NULL, NULL, run); + GNUNET_break (NULL != op); + peers_running += run ? 1 : -1; + GNUNET_assert (peers_running > 0); + } +} + + +/** + * @brief Move to next round. + * + * @param cls Closure (round #). + * @param tc Task context. + */ +static void +next_rnd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0) + return; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "ROUND %ld\n", current_round); + if (0.0 == rounds[current_round]) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Finishing\n"); + GNUNET_SCHEDULER_add_now (&finish_profiler, NULL); + return; + } + adjust_running_peers (rounds[current_round] * peers_total); + current_round++; + + GNUNET_SCHEDULER_add_delayed (round_time, &next_rnd, NULL); +} + + +/** + * Transmit ping callback. + * + * @param cls Closure (peer for PING, NULL for PONG). + * @param size Size of the tranmist buffer. + * @param buf Pointer to the beginning of the buffer. + * + * @return Number of bytes written to buf. + */ +static size_t +tmt_rdy_ping (void *cls, size_t size, void *buf); + + +/** + * Transmit pong callback. + * + * @param cls Closure (copy of PING message, to be freed). + * @param size Size of the buffer we have. + * @param buf Buffer to copy data to. + */ +static size_t +tmt_rdy_pong (void *cls, size_t size, void *buf) +{ + struct CadetPingMessage *ping = cls; + struct CadetPingMessage *pong; + + if (0 == size || NULL == buf) + { + GNUNET_free (ping); + return 0; + } + pong = (struct CadetPingMessage *) buf; + memcpy (pong, ping, sizeof (*ping)); + pong->header.type = htons (PONG); + + GNUNET_free (ping); + return sizeof (*ping); +} + + +/** + * @brief Send a ping to destination + * + * @param cls Closure (peer). + * @param tc Task context. + */ +static void +ping (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CadetPeer *peer = (struct CadetPeer *) cls; + + peer->ping_task = GNUNET_SCHEDULER_NO_TASK; + + if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0 + || GNUNET_YES == test_finished) + return; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u -> %u (%u)\n", + get_index (peer), get_index (peer->dest), peer->data_sent); + + GNUNET_CADET_notify_transmit_ready (peer->ch, GNUNET_NO, + GNUNET_TIME_UNIT_FOREVER_REL, + sizeof (struct CadetPingMessage), + &tmt_rdy_ping, peer); +} + +/** + * @brief Reply with a pong to origin. + * + * @param cls Closure (peer). + * @param tc Task context. + */ +static void +pong (struct GNUNET_CADET_Channel *channel, const struct CadetPingMessage *ping) +{ + struct CadetPingMessage *copy; + + copy = GNUNET_new (struct CadetPingMessage); + memcpy (copy, ping, sizeof (*ping)); + GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO, + GNUNET_TIME_UNIT_FOREVER_REL, + sizeof (struct CadetPingMessage), + &tmt_rdy_pong, copy); +} + + +/** + * Transmit ping callback + * + * @param cls Closure (peer). + * @param size Size of the buffer we have. + * @param buf Buffer to copy data to. + */ +static size_t +tmt_rdy_ping (void *cls, size_t size, void *buf) +{ + struct CadetPeer *peer = (struct CadetPeer *) cls; + struct CadetPingMessage *msg = buf; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tmt_rdy called, filling buffer\n"); + if (size < sizeof (struct CadetPingMessage) || NULL == buf) + { + GNUNET_break (GNUNET_YES == test_finished); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "size %u, buf %p, data_sent %u, data_received %u\n", + size, buf, peer->data_sent, peer->data_received); + + return 0; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending: msg %d\n", peer->data_sent); + msg->header.size = htons (size); + msg->header.type = htons (PING); + msg->counter = htonl (peer->data_sent++); + msg->round_number = htonl (current_round); + msg->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); + peer->pings[current_round]++; + peer->ping_task = GNUNET_SCHEDULER_add_delayed (delay_ms_rnd (PING_PERIOD), + &ping, peer); + + return sizeof (struct CadetPingMessage); +} + + +/** + * Function is called whenever a PING message is received. + * + * @param cls closure (peer #, set from GNUNET_CADET_connect) + * @param channel connection to the other end + * @param channel_ctx place to store local state associated with the channel + * @param message the actual message + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +ping_handler (void *cls, struct GNUNET_CADET_Channel *channel, + void **channel_ctx, + const struct GNUNET_MessageHeader *message) +{ + long n = (long) cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%u got PING\n", n); + GNUNET_CADET_receive_done (channel); + if (GNUNET_NO == test_finished) + pong (channel, (struct CadetPingMessage *) message); + + return GNUNET_OK; +} + + +/** + * Function is called whenever a PONG message is received. + * + * @param cls closure (peer #, set from GNUNET_CADET_connect) + * @param channel connection to the other end + * @param channel_ctx place to store local state associated with the channel + * @param message the actual message + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +pong_handler (void *cls, struct GNUNET_CADET_Channel *channel, + void **channel_ctx, + const struct GNUNET_MessageHeader *message) +{ + long n = (long) cls; + struct CadetPeer *peer; + struct CadetPingMessage *msg; + struct GNUNET_TIME_Absolute send_time; + struct GNUNET_TIME_Relative latency; + unsigned int r /* Ping round */; + float delta; + + GNUNET_CADET_receive_done (channel); + peer = &peers[n]; + + msg = (struct CadetPingMessage *) message; + + send_time = GNUNET_TIME_absolute_ntoh (msg->timestamp); + latency = GNUNET_TIME_absolute_get_duration (send_time); + r = ntohl (msg->round_number); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u <- %u (%u) latency: %s\n", + get_index (peer), get_index (peer->dest), ntohl (msg->counter), + GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO)); + + /* Online variance calculation */ + peer->pongs[r]++; + delta = latency.rel_value_us - peer->mean[r]; + peer->mean[r] = peer->mean[r] + delta/peer->pongs[r]; + peer->var[r] += delta * (latency.rel_value_us - peer->mean[r]); + + return GNUNET_OK; +} + + +/** + * Handlers, for diverse services + */ +static struct GNUNET_CADET_MessageHandler handlers[] = { + {&ping_handler, PING, sizeof (struct CadetPingMessage)}, + {&pong_handler, PONG, sizeof (struct CadetPingMessage)}, + {NULL, 0, 0} +}; + + +/** + * Method called whenever another peer has added us to a channel + * the other peer initiated. + * + * @param cls Closure. + * @param channel New handle to the channel. + * @param initiator Peer that started the channel. + * @param port Port this channel is connected to. + * @param options channel option flags + * @return Initial channel context for the channel + * (can be NULL -- that's not an error). + */ +static void * +incoming_channel (void *cls, struct GNUNET_CADET_Channel *channel, + const struct GNUNET_PeerIdentity *initiator, + uint32_t port, enum GNUNET_CADET_ChannelOption options) +{ + long n = (long) cls; + struct CadetPeer *peer; + + peer = GNUNET_CONTAINER_multipeermap_get (ids, initiator); + GNUNET_assert (NULL != peer); + if (NULL == peers[n].incoming) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "WARMUP %3u: %u <= %u\n", + peers_warmup, n, get_index (peer)); + peers_warmup++; + if (peers_warmup < peers_total) + return NULL; + if (GNUNET_SCHEDULER_NO_TASK != test_task) + { + GNUNET_SCHEDULER_cancel (test_task); + test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &start_test, NULL); + } + return NULL; + } + GNUNET_assert (peer == peers[n].incoming); + GNUNET_assert (peer->dest == &peers[n]); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u <= %u %p\n", + n, get_index (peer), channel); + peers[n].incoming_ch = channel; + + return NULL; +} + +/** + * Function called whenever an inbound channel is destroyed. Should clean up + * any associated state. + * + * @param cls closure (set from GNUNET_CADET_connect) + * @param channel connection to the other end (henceforth invalid) + * @param channel_ctx place where local state associated + * with the channel is stored + */ +static void +channel_cleaner (void *cls, const struct GNUNET_CADET_Channel *channel, + void *channel_ctx) +{ + long n = (long) cls; + struct CadetPeer *peer = &peers[n]; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Channel %p disconnected at peer %ld\n", channel, n); + if (peer->ch == channel) + peer->ch = NULL; +} + + +/** + * Select a random peer that has no incoming channel + * + * @param peer ID of the peer connecting. NULL if irrelevant (warmup). + * + * @return Random peer not yet connected to. + */ +static struct CadetPeer * +select_random_peer (struct CadetPeer *peer) +{ + unsigned int r; + + do + { + r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, peers_total); + } while (NULL != peers[r].incoming); + peers[r].incoming = peer; + + return &peers[r]; +} + +/** + * START THE TEST ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES. + * + * Testcase continues when the root receives confirmation of connected peers, + * on callback funtion ch. + * + * @param cls Closure (unsued). + * @param tc Task Context. + */ +static void +start_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + enum GNUNET_CADET_ChannelOption flags; + unsigned long i; + + test_task = GNUNET_SCHEDULER_NO_TASK; + if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0) + return; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Start profiler\n"); + + flags = GNUNET_CADET_OPTION_DEFAULT; + for (i = 0; i < peers_pinging; i++) + { + peers[i].dest = select_random_peer (&peers[i]); + peers[i].ch = GNUNET_CADET_channel_create (peers[i].cadet, NULL, + &peers[i].dest->id, + 1, flags); + if (NULL == peers[i].ch) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Channel %lu failed\n", i); + GNUNET_CADET_TEST_cleanup (test_ctx); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u => %u %p\n", + i, get_index (peers[i].dest), peers[i].ch); + peers[i].ping_task = GNUNET_SCHEDULER_add_delayed (delay_ms_rnd (2000), + &ping, &peers[i]); + } + peers_running = peers_total; + if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(round_time, + number_rounds + 1), + &disconnect_cadet_peers, + (void *) __LINE__); + GNUNET_SCHEDULER_add_delayed (round_time, &next_rnd, NULL); +} + + +/** + * Do warmup: create some channels to spread information about the topology. + */ +static void +warmup (void) +{ + struct CadetPeer *peer; + unsigned int i; + + for (i = 0; i < peers_total; i++) + { + peer = select_random_peer (NULL); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "WARMUP %u => %u\n", + i, get_index (peer)); + peers[i].warmup_ch = + GNUNET_CADET_channel_create (peers[i].cadet, NULL, &peer->id, + 1, GNUNET_CADET_OPTION_DEFAULT); + if (NULL == peers[i].warmup_ch) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Warmup %u failed\n", i); + GNUNET_CADET_TEST_cleanup (test_ctx); + return; + } + } +} + +/** + * Callback to be called when the requested peer information is available + * + * @param cls the closure from GNUNET_TESTBED_peer_get_information() + * @param op the operation this callback corresponds to + * @param pinfo the result; will be NULL if the operation has failed + * @param emsg error message if the operation has failed; + * NULL if the operation is successfull + */ +static void +peer_id_cb (void *cls, + struct GNUNET_TESTBED_Operation *op, + const struct GNUNET_TESTBED_PeerInformation *pinfo, + const char *emsg) +{ + long n = (long) cls; + + if (NULL == pinfo || NULL != emsg) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg); + abort_test (__LINE__); + return; + } + peers[n].id = *(pinfo->result.id); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, " %u id: %s\n", + n, GNUNET_i2s (&peers[n].id)); + GNUNET_break (GNUNET_OK == + GNUNET_CONTAINER_multipeermap_put (ids, &peers[n].id, &peers[n], + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); + + GNUNET_TESTBED_operation_done (peers[n].op); + peers[n].op = NULL; + + p_ids++; + if (p_ids < peers_total) + return; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got all IDs, starting profiler\n"); + if (do_warmup) + { + struct GNUNET_TIME_Relative delay; + + warmup(); + delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, + 100 * peers_total); + test_task = GNUNET_SCHEDULER_add_delayed (delay, &start_test, NULL); + return; /* start_test from incoming_channel */ + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Starting in a second...\n"); + test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &start_test, NULL); +} + +/** + * test main: start test when all peers are connected + * + * @param cls Closure. + * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end. + * @param num_peers Number of peers that are running. + * @param testbed_peers Array of peers. + * @param cadetes Handle to each of the CADETs of the peers. + */ +static void +tmain (void *cls, + struct GNUNET_CADET_TEST_Context *ctx, + unsigned int num_peers, + struct GNUNET_TESTBED_Peer **testbed_peers, + struct GNUNET_CADET_Handle **cadetes) +{ + unsigned long i; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n"); + test_ctx = ctx; + GNUNET_assert (peers_total == num_peers); + peers_running = num_peers; + testbed_handles = testbed_peers; + disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, + &disconnect_cadet_peers, + (void *) __LINE__); + shutdown_handle = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &shutdown_task, NULL); + for (i = 0; i < peers_total; i++) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requesting id %ld\n", i); + peers[i].up = GNUNET_YES; + peers[i].cadet = cadetes[i]; + peers[i].op = + GNUNET_TESTBED_peer_get_information (testbed_handles[i], + GNUNET_TESTBED_PIT_IDENTITY, + &peer_id_cb, (void *) i); + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "requested peer ids\n"); + /* Continues from pi_cb -> do_test */ +} + + +/** + * Main: start profiler. + */ +int +main (int argc, char *argv[]) +{ + static uint32_t ports[2]; + const char *config_file; + + config_file = ".profiler.conf"; + + if (4 > argc) + { + fprintf (stderr, "usage: %s ROUND_TIME PEERS PINGS [DO_WARMUP]\n", argv[0]); + fprintf (stderr, "example: %s 30s 16 1 Y\n", argv[0]); + return 1; + } + + if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_relative (argv[1], &round_time)) + { + fprintf (stderr, "%s is not a valid time\n", argv[1]); + return 1; + } + + peers_total = atoll (argv[2]); + if (2 > peers_total) + { + fprintf (stderr, "%s peers is not valid (> 2)\n", argv[1]); + return 1; + } + peers = GNUNET_malloc (sizeof (struct CadetPeer) * peers_total); + + peers_pinging = atoll (argv[3]); + + if (peers_total < 2 * peers_pinging) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "not enough peers, total should be > 2 * peers_pinging\n"); + return 1; + } + + do_warmup = (5 > argc || argv[4][0] != 'N'); + + ids = GNUNET_CONTAINER_multipeermap_create (2 * peers_total, GNUNET_YES); + GNUNET_assert (NULL != ids); + p_ids = 0; + test_finished = GNUNET_NO; + ports[0] = 1; + ports[1] = 0; + GNUNET_CADET_TEST_run ("cadet-profiler", config_file, peers_total, + &tmain, NULL, /* tmain cls */ + &incoming_channel, &channel_cleaner, + handlers, ports); + GNUNET_free (peers); + + return 0; +} + +/* end of gnunet-cadet-profiler.c */ + diff --git a/src/cadet/gnunet-cadet.c b/src/cadet/gnunet-cadet.c new file mode 100644 index 000000000..840c6d0ac --- /dev/null +++ b/src/cadet/gnunet-cadet.c @@ -0,0 +1,851 @@ +/* + This file is part of GNUnet. + (C) 2012 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 cadet/gnunet-cadet.c + * @brief Print information about cadet tunnels and peers. + * @author Bartlomiej Polot + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_cadet_service.h" +#include "cadet.h" + + +/** + * Option -m. + */ +static int monitor_connections; + +/** + * Option -P. + */ +static int request_peers; + +/** + * Option --peer + */ +static char *peer_id; + +/** + * Option -T. + */ +static int request_tunnels; + +/** + * Option --tunnel + */ +static char *tunnel_id; + +/** + * Option --connection + */ +static char *conn_id; + +/** + * Option --channel + */ +static char *channel_id; + +/** + * Port to listen on (-p). + */ +static uint32_t listen_port; + +/** + * Request echo service + */ +int echo; + +/** + * Time of last echo request. + */ +struct GNUNET_TIME_Absolute echo_time; + +/** + * Task for next echo request. + */ +GNUNET_SCHEDULER_TaskIdentifier echo_task; + +/** + * Peer to connect to. + */ +static char *target_id; + +/** + * Port to connect to + */ +static uint32_t target_port; + +/** + * Data pending in netcat mode. + */ +size_t data_size; + + +/** + * Cadet handle. + */ +static struct GNUNET_CADET_Handle *mh; + +/** + * Channel handle. + */ +static struct GNUNET_CADET_Channel *ch; + +/** + * Shutdown task handle. + */ +GNUNET_SCHEDULER_TaskIdentifier sd; + + + +static void +listen_stdio (void); + + + +/** + * Task run in monitor mode when the user presses CTRL-C to abort. + * Stops monitoring activity. + * + * @param cls Closure (unused). + * @param tc scheduler context + */ +static void +shutdown_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n"); + if (NULL != ch) + { + GNUNET_CADET_channel_destroy (ch); + ch = NULL; + } + if (NULL != mh) + { + GNUNET_CADET_disconnect (mh); + mh = NULL; + } +} + + +/** + * Function called to notify a client about the connection + * begin ready to queue more data. "buf" will be + * NULL and "size" zero if the connection was closed for + * writing in the meantime. + * + * FIXME + * + * @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 + */ +size_t +data_ready (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader *msg; + size_t total_size; + + if (NULL == buf || 0 == size) + { + GNUNET_SCHEDULER_shutdown(); + return 0; + } + + total_size = data_size + sizeof (struct GNUNET_MessageHeader); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending %u bytes\n", data_size); + GNUNET_assert (size >= total_size); + + msg = buf; + msg->size = htons (total_size); + msg->type = htons (GNUNET_MESSAGE_TYPE_CADET_CLI); + memcpy (&msg[1], cls, data_size); + if (GNUNET_NO == echo) + { + listen_stdio (); + } + else + { + echo_time = GNUNET_TIME_absolute_get (); + } + + return total_size; +} + + +/** + * Task run in monitor mode when the user presses CTRL-C to abort. + * Stops monitoring activity. + * + * @param cls Closure (unused). + * @param tc scheduler context + */ +static void +read_stdio (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + static char buf[60000]; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + { + return; + } + + data_size = read (0, buf, 60000); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "stdio read %u bytes\n", data_size); + if (data_size < 1) + { + GNUNET_SCHEDULER_shutdown(); + return; + } + GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO, + GNUNET_TIME_UNIT_FOREVER_REL, + data_size + + sizeof (struct GNUNET_MessageHeader), + &data_ready, buf); +} + + +/** + * Start listening to stdin + */ +static void +listen_stdio (void) +{ + struct GNUNET_NETWORK_FDSet *rs; + + rs = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_set_native (rs, 0); + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_TIME_UNIT_FOREVER_REL, + rs, NULL, + &read_stdio, NULL); + GNUNET_NETWORK_fdset_destroy (rs); +} + + +/** + * Function called whenever a channel is destroyed. Should clean up + * any associated state. + * + * It must NOT call #GNUNET_CADET_channel_destroy on the channel. + * + * @param cls closure (set from #GNUNET_CADET_connect) + * @param channel connection to the other end (henceforth invalid) + * @param channel_ctx place where local state associated + * with the channel is stored + */ +static void +channel_ended (void *cls, + const struct GNUNET_CADET_Channel *channel, + void *channel_ctx) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel ended!\n"); + GNUNET_break (channel == ch); + ch = NULL; + GNUNET_SCHEDULER_shutdown (); +} + + +/** + * Method called whenever another peer has added us to a channel + * the other peer initiated. + * Only called (once) upon reception of data with a message type which was + * subscribed to in #GNUNET_CADET_connect. + * + * A call to #GNUNET_CADET_channel_destroy causes te channel to be ignored. In + * this case the handler MUST return NULL. + * + * @param cls closure + * @param channel new handle to the channel + * @param initiator peer that started the channel + * @param port Port this channel is for. + * @param options CadetOption flag field, with all active option bits set to 1. + * + * @return initial channel context for the channel + * (can be NULL -- that's not an error) + */ +static void * +channel_incoming (void *cls, + struct GNUNET_CADET_Channel * channel, + const struct GNUNET_PeerIdentity * initiator, + uint32_t port, enum GNUNET_CADET_ChannelOption options) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Incoming channel %p on port %u\n", + channel, port); + if (NULL != ch) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "A channel already exists\n"); + return NULL; + } + if (0 == listen_port) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not listening to channels\n"); + return NULL; + } + ch = channel; + if (GNUNET_NO == echo) + { + listen_stdio (); + return NULL; + } + data_size = 0; + return NULL; +} + +/** + * @brief Send an echo request to the remote peer. + * + * @param cls Closure (NULL). + * @param tc Task context. + */ +static void +send_echo (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) || NULL == ch) + return; + + GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO, + GNUNET_TIME_UNIT_FOREVER_REL, + sizeof (struct GNUNET_MessageHeader), + &data_ready, NULL); +} + + + +/** + * Call CADET's monitor API, get info of one connection. + * + * @param cls Closure (unused). + * @param tc TaskContext + */ +static void +create_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_PeerIdentity pid; + enum GNUNET_CADET_ChannelOption opt; + + GNUNET_assert (NULL == ch); + + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_public_key_from_string (target_id, + strlen (target_id), + &pid.public_key)) + { + FPRINTF (stderr, + _("Invalid target `%s'\n"), + target_id); + GNUNET_SCHEDULER_shutdown (); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to `%s'\n", target_id); + opt = GNUNET_CADET_OPTION_DEFAULT | GNUNET_CADET_OPTION_RELIABLE; + ch = GNUNET_CADET_channel_create (mh, NULL, &pid, target_port, opt); + if (GNUNET_NO == echo) + listen_stdio (); + else + GNUNET_SCHEDULER_add_now (send_echo, NULL); +} + + +/** + * Function called whenever a message is received. + * + * Each time the function must call #GNUNET_CADET_receive_done on the channel + * in order to receive the next message. This doesn't need to be immediate: + * can be delayed if some processing is done on the message. + * + * @param cls Closure (set from #GNUNET_CADET_connect). + * @param channel Connection to the other end. + * @param channel_ctx Place to store local state associated with the channel. + * @param message The actual message. + * @return #GNUNET_OK to keep the channel open, + * #GNUNET_SYSERR to close it (signal serious error). + */ +static int +data_callback (void *cls, + struct GNUNET_CADET_Channel *channel, + void **channel_ctx, + const struct GNUNET_MessageHeader *message) +{ + uint16_t len; + ssize_t done; + uint16_t off; + const char *buf; + GNUNET_break (ch == channel); + + if (GNUNET_YES == echo) + { + if (0 != listen_port) + { + /* Just listening to echo incoming messages*/ + GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO, + GNUNET_TIME_UNIT_FOREVER_REL, + sizeof (struct GNUNET_MessageHeader), + &data_ready, NULL); + return GNUNET_OK; + } + else + { + struct GNUNET_TIME_Relative latency; + + latency = GNUNET_TIME_absolute_get_duration (echo_time); + echo_time = GNUNET_TIME_UNIT_FOREVER_ABS; + FPRINTF (stdout, "time: %s\n", + GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO)); + echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &send_echo, NULL); + } + } + + len = ntohs (message->size) - sizeof (*message); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u bytes\n", len); + buf = (const char *) &message[1]; + off = 0; + while (off < len) + { + done = write (1, &buf[off], len - off); + if (done <= 0) + { + if (-1 == done) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "write"); + return GNUNET_SYSERR; + } + off += done; + } + return GNUNET_OK; +} + + +/** + * Method called to retrieve information about all peers in CADET, called + * once per peer. + * + * After last peer has been reported, an additional call with NULL is done. + * + * @param cls Closure. + * @param peer Peer, or NULL on "EOF". + * @param tunnel Do we have a tunnel towards this peer? + * @param n_paths Number of known paths towards this peer. + * @param best_path How long is the best path? + * (0 = unknown, 1 = ourselves, 2 = neighbor) + */ +static void +peers_callback (void *cls, const struct GNUNET_PeerIdentity *peer, + int tunnel, unsigned int n_paths, unsigned int best_path) +{ + if (NULL == peer) + { + if (GNUNET_YES != monitor_connections) + { + GNUNET_SCHEDULER_shutdown(); + } + return; + } + FPRINTF (stdout, "%s tunnel: %c, paths: %u\n", + GNUNET_i2s_full (peer), tunnel ? 'Y' : 'N', n_paths); +} + +/** + * Method called to retrieve information about a specific peer + * known to the service. + * + * @param cls Closure. + * @param peer Peer ID. + * @param tunnel Do we have a tunnel towards this peer? #GNUNET_YES/#GNUNET_NO + * @param neighbor Is this a direct neighbor? #GNUNET_YES/#GNUNET_NO + * @param n_paths Number of paths known towards peer. + * @param paths Array of PEER_IDs representing all paths to reach the peer. + * Each path starts with the local peer. + * Each path ends with the destination peer (given in @c peer). + */ +void +peer_callback (void *cls, + const struct GNUNET_PeerIdentity *peer, + int tunnel, + int neighbor, + unsigned int n_paths, + struct GNUNET_PeerIdentity *paths) +{ +} + + +/** + * Method called to retrieve information about all tunnels in CADET. + * + * @param cls Closure. + * @param peer Destination peer. + * @param channels Number of channels. + * @param connections Number of connections. + * @param estate Encryption state. + * @param cstate Connectivity state. + */ +void +tunnels_callback (void *cls, + const struct GNUNET_PeerIdentity *peer, + unsigned int channels, + unsigned int connections, + uint16_t estate, + uint16_t cstate) +{ + if (NULL == peer) + { + if (GNUNET_YES != monitor_connections) + { + GNUNET_SCHEDULER_shutdown(); + } + return; + } + FPRINTF (stdout, "%s [ENC: %u, CON: %u] CHs: %u, CONNs: %u\n", + GNUNET_i2s_full (peer), estate, cstate, channels, connections); +} + + +/** + * Method called to retrieve information about a specific tunnel the cadet peer + * has established, o`r is trying to establish. + * + * @param cls Closure. + * @param peer Peer towards whom the tunnel is directed. + * @param n_channels Number of channels. + * @param n_connections Number of connections. + * @param channels Channels. + * @param connections Connections. + * @param estate Encryption status. + * @param cstate Connectivity status. + */ +void +tunnel_callback (void *cls, + const struct GNUNET_PeerIdentity *peer, + unsigned int n_channels, + unsigned int n_connections, + uint32_t *channels, + struct GNUNET_CADET_Hash *connections, + unsigned int estate, + unsigned int cstate) +{ + unsigned int i; + + if (NULL != peer) + { + FPRINTF (stdout, "Tunnel %s\n", GNUNET_i2s_full (peer)); + FPRINTF (stdout, "- %u channels\n", n_channels); + for (i = 0; i < n_channels; i++) + FPRINTF (stdout, " %u\n", channels[i]); + FPRINTF (stdout, "- %u connections\n", n_connections); + for (i = 0; i < n_connections; i++) + FPRINTF (stdout, " %s\n", GM_h2s (&connections[i])); + FPRINTF (stdout, "- enc state: %u\n", estate); + FPRINTF (stdout, "- con state: %u\n", cstate); + } + if (GNUNET_YES != monitor_connections) + { + GNUNET_SCHEDULER_shutdown(); + } + return; + +} + + +/** + * Call CADET's meta API, get all peers known to a peer. + * + * @param cls Closure (unused). + * @param tc TaskContext + */ +static void +get_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n"); + return; + } + GNUNET_CADET_get_peers (mh, &peers_callback, NULL); +} + + +/** + * Call CADET's monitor API, get info of one peer. + * + * @param cls Closure (unused). + * @param tc TaskContext + */ +static void +show_peer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_PeerIdentity pid; + + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id, + strlen (peer_id), + &pid.public_key)) + { + fprintf (stderr, + _("Invalid peer ID `%s'\n"), + peer_id); + GNUNET_SCHEDULER_shutdown(); + return; + } + GNUNET_CADET_get_peer (mh, &pid, peer_callback, NULL); +} + +/** + * Call CADET's meta API, get all tunnels known to a peer. + * + * @param cls Closure (unused). + * @param tc TaskContext + */ +static void +get_tunnels (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n"); + return; + } + GNUNET_CADET_get_tunnels (mh, &tunnels_callback, NULL); +} + + +/** + * Call CADET's monitor API, get info of one tunnel. + * + * @param cls Closure (unused). + * @param tc TaskContext + */ +static void +show_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_PeerIdentity pid; + + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_public_key_from_string (tunnel_id, + strlen (tunnel_id), + &pid.public_key)) + { + fprintf (stderr, + _("Invalid tunnel owner `%s'\n"), + tunnel_id); + GNUNET_SCHEDULER_shutdown(); + return; + } + GNUNET_CADET_get_tunnel (mh, &pid, tunnel_callback, NULL); +} + + +/** + * Call CADET's monitor API, get info of one channel. + * + * @param cls Closure (unused). + * @param tc TaskContext + */ +static void +show_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + +} + + +/** + * Call CADET's monitor API, get info of one connection. + * + * @param cls Closure (unused). + * @param tc TaskContext + */ +static void +show_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + +} + + +/** + * 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) +{ + GNUNET_CADET_InboundChannelNotificationHandler *newch = NULL; + GNUNET_CADET_ChannelEndHandler *endch = NULL; + static const struct GNUNET_CADET_MessageHandler handlers[] = { + {&data_callback, GNUNET_MESSAGE_TYPE_CADET_CLI, 0}, + {NULL, 0, 0} /* FIXME add option to monitor msg types */ + }; + static uint32_t *ports = NULL; + /* FIXME add option to monitor apps */ + + target_id = args[0]; + target_port = args[0] && args[1] ? atoi(args[1]) : 0; + if ( (0 != (request_peers | request_tunnels) + || 0 != monitor_connections + || NULL != tunnel_id + || NULL != conn_id + || NULL != channel_id) + && target_id != NULL) + { + FPRINTF (stderr, + _("You must NOT give a TARGET" + "when using 'request all' options\n")); + return; + } + + if (NULL != target_id) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating channel to %s\n", + target_id); + GNUNET_SCHEDULER_add_now (&create_channel, NULL); + endch = &channel_ended; + } + else if (0 != listen_port) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Listen\n"); + newch = &channel_incoming; + endch = &channel_ended; + ports = GNUNET_malloc (sizeof (uint32_t) * 2); + ports[0] = listen_port; + } + else if (NULL != peer_id) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show peer\n"); + GNUNET_SCHEDULER_add_now (&show_peer, NULL); + } + else if (NULL != tunnel_id) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show tunnel\n"); + GNUNET_SCHEDULER_add_now (&show_tunnel, NULL); + } + else if (NULL != channel_id) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show channel\n"); + GNUNET_SCHEDULER_add_now (&show_channel, NULL); + } + else if (NULL != conn_id) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show connection\n"); + GNUNET_SCHEDULER_add_now (&show_connection, NULL); + } + else if (GNUNET_YES == request_peers) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all peers\n"); + GNUNET_SCHEDULER_add_now (&get_peers, NULL); + } + else if (GNUNET_YES == request_tunnels) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all tunnels\n"); + GNUNET_SCHEDULER_add_now (&get_tunnels, NULL); + } + else + { + FPRINTF (stderr, "No action requested\n"); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to cadet\n"); + mh = GNUNET_CADET_connect (cfg, + NULL, /* cls */ + newch, /* new channel */ + endch, /* cleaner */ + handlers, + ports); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done\n"); + if (NULL == mh) + GNUNET_SCHEDULER_add_now (shutdown_task, NULL); + else + sd = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + shutdown_task, NULL); + +} + + +/** + * The main function to obtain peer information. + * + * @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) +{ + int res; + const char helpstr[] = "Create channels and retreive info about cadets status."; + static const struct GNUNET_GETOPT_CommandLineOption options[] = { +// {'a', "channel", "TUNNEL_ID:CHANNEL_ID", +// gettext_noop ("provide information about a particular channel"), +// GNUNET_YES, &GNUNET_GETOPT_set_string, &channel_id}, + {'C', "connection", "CONNECTION_ID", + gettext_noop ("provide information about a particular connection"), + GNUNET_YES, &GNUNET_GETOPT_set_string, &conn_id}, + {'e', "echo", NULL, + gettext_noop ("activate echo mode"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &echo}, +// {'m', "monitor", NULL, +// gettext_noop ("provide information about all events (continuously)"), +// GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor_mode}, + {'o', "open-port", NULL, + gettext_noop ("port to listen to (default; 0)"), + GNUNET_YES, &GNUNET_GETOPT_set_uint, &listen_port}, + {'p', "peer", "PEER_ID", + gettext_noop ("provide information about a patricular peer"), + GNUNET_YES, &GNUNET_GETOPT_set_string, &peer_id}, + {'P', "peers", NULL, + gettext_noop ("provide information about all peers"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &request_peers}, + {'t', "tunnel", "TUNNEL_ID", + gettext_noop ("provide information about a particular tunnel"), + GNUNET_YES, &GNUNET_GETOPT_set_string, &tunnel_id}, + {'T', "tunnels", NULL, + gettext_noop ("provide information about all tunnels"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &request_tunnels}, + + GNUNET_GETOPT_OPTION_END + }; + + monitor_connections = GNUNET_NO; + + if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) + return 2; + + res = GNUNET_PROGRAM_run (argc, argv, "gnunet-cadet (OPTIONS | TARGET PORT)", + gettext_noop (helpstr), + options, &run, NULL); + + GNUNET_free ((void *) argv); + + if (GNUNET_OK == res) + return 0; + else + return 1; +} + +/* end of gnunet-cadet.c */ diff --git a/src/cadet/gnunet-service-cadet.c b/src/cadet/gnunet-service-cadet.c new file mode 100644 index 000000000..de9aaf7a5 --- /dev/null +++ b/src/cadet/gnunet-service-cadet.c @@ -0,0 +1,181 @@ +/* + This file is part of GNUnet. + (C) 2001-2013 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 cadet/gnunet-service-cadet.c + * @brief GNUnet CADET service with encryption + * @author Bartlomiej Polot + * + * FIXME in progress: + * - rekey - reliability interaction + * - channel retransmit timing + * + * TODO: + * - relay corking down to core + * - set ttl relative to path length + * TODO END + * + * Dictionary: + * - peer: other cadet instance. If there is direct connection it's a neighbor. + * - tunnel: encrypted connection to a peer, neighbor or not. + * - channel: connection between two clients, on the same or different peers. + * have properties like reliability. + * - path: series of directly connected peer from one peer to another. + * - connection: path which is being used in a tunnel. + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "cadet.h" +#include "gnunet_statistics_service.h" + +#include "gnunet-service-cadet_local.h" +#include "gnunet-service-cadet_channel.h" +#include "gnunet-service-cadet_connection.h" +#include "gnunet-service-cadet_tunnel.h" +#include "gnunet-service-cadet_dht.h" +#include "gnunet-service-cadet_peer.h" +#include "gnunet-service-cadet_hello.h" + + +/******************************************************************************/ +/*********************** GLOBAL VARIABLES ****************************/ +/******************************************************************************/ + +/****************************** Global variables ******************************/ + +/** + * Handle to the statistics service. + */ +struct GNUNET_STATISTICS_Handle *stats; + +/** + * Local peer own ID (memory efficient handle). + */ +GNUNET_PEER_Id myid; + +/** + * Local peer own ID (full value). + */ +struct GNUNET_PeerIdentity my_full_id; + + +/** + * Signal that shutdown is happening: prevent recover measures. + */ +int shutting_down; + +/*************************** Static global variables **************************/ + +/** + * Own private key. + */ +static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key; + + +/******************************************************************************/ +/************************ MAIN FUNCTIONS ****************************/ +/******************************************************************************/ + +/** + * Task run during shutdown. + * + * @param cls unused + * @param tc unused + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutting down\n"); + + shutting_down = GNUNET_YES; + + GML_shutdown (); + GMH_shutdown (); + GMC_shutdown (); + GMT_shutdown (); + GMD_shutdown (); + GMP_shutdown (); + + GNUNET_STATISTICS_destroy (stats, GNUNET_NO); + stats = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shut down\n"); +} + + +/** + * Process cadet requests. + * + * @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) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting to run\n"); + + stats = GNUNET_STATISTICS_create ("cadet", c); + + /* Scheduled the task to clean up when shutdown is called */ + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + NULL); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "reading key\n"); + my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c); + GNUNET_assert (NULL != my_private_key); + GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_full_id.public_key); + myid = GNUNET_PEER_intern (&my_full_id); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "STARTING SERVICE (CADET) for peer [%s]\n", + GNUNET_i2s (&my_full_id)); + + GML_init (server); /* Local clients */ + GMH_init (c); /* Hellos */ + GMC_init (c); /* Connections */ + GMP_init (c); /* Peers */ + GMD_init (c); /* DHT */ + GMT_init (c, my_private_key); /* Tunnels */ + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cadet service running\n"); +} + + +/** + * The main function for the cadet 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) +{ + int ret; + int r; + + shutting_down = GNUNET_NO; + r = GNUNET_SERVICE_run (argc, argv, "cadet", GNUNET_SERVICE_OPTION_NONE, &run, + NULL); + GNUNET_free (my_private_key); + ret = (GNUNET_OK == r) ? 0 : 1; + + return ret; +} diff --git a/src/cadet/gnunet-service-cadet_channel.c b/src/cadet/gnunet-service-cadet_channel.c new file mode 100644 index 000000000..91338d5c0 --- /dev/null +++ b/src/cadet/gnunet-service-cadet_channel.c @@ -0,0 +1,2432 @@ +/* + This file is part of GNUnet. + (C) 2013 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_util_lib.h" + +#include "gnunet_statistics_service.h" + +#include "cadet.h" +#include "cadet_protocol.h" + +#include "gnunet-service-cadet_channel.h" +#include "gnunet-service-cadet_local.h" +#include "gnunet-service-cadet_tunnel.h" +#include "gnunet-service-cadet_peer.h" + +#define LOG(level, ...) GNUNET_log_from(level,"cadet-chn",__VA_ARGS__) + +#define CADET_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(\ + GNUNET_TIME_UNIT_MILLISECONDS, 250) +#define CADET_RETRANSMIT_MARGIN 4 + + +/** + * All the states a connection can be in. + */ +enum CadetChannelState +{ + /** + * Uninitialized status, should never appear in operation. + */ + CADET_CHANNEL_NEW, + + /** + * Connection create message sent, waiting for ACK. + */ + CADET_CHANNEL_SENT, + + /** + * Connection confirmed, ready to carry traffic. + */ + CADET_CHANNEL_READY, +}; + + +/** + * Info holder for channel messages in queues. + */ +struct CadetChannelQueue +{ + /** + * Tunnel Queue. + */ + struct CadetTunnel3Queue *tq; + + /** + * Message type (DATA/DATA_ACK) + */ + uint16_t type; + + /** + * Message copy (for DATAs, to start retransmission timer) + */ + struct CadetReliableMessage *copy; + + /** + * Reliability (for DATA_ACKs, to access rel->ack_q) + */ + struct CadetChannelReliability *rel; +}; + + +/** + * Info needed to retry a message in case it gets lost. + */ +struct CadetReliableMessage +{ + /** + * Double linked list, FIFO style + */ + struct CadetReliableMessage *next; + struct CadetReliableMessage *prev; + + /** + * Type of message (payload, channel management). + */ + int16_t type; + + /** + * Tunnel Reliability queue this message is in. + */ + struct CadetChannelReliability *rel; + + /** + * ID of the message (ACK needed to free) + */ + uint32_t mid; + + /** + * Tunnel Queue. + */ + struct CadetChannelQueue *chq; + + /** + * When was this message issued (to calculate ACK delay) + */ + struct GNUNET_TIME_Absolute timestamp; + + /* struct GNUNET_CADET_Data with payload */ +}; + + +/** + * Info about the traffic state for a client in a channel. + */ +struct CadetChannelReliability +{ + /** + * Channel this is about. + */ + struct CadetChannel *ch; + + /** + * DLL of messages sent and not yet ACK'd. + */ + struct CadetReliableMessage *head_sent; + struct CadetReliableMessage *tail_sent; + + /** + * DLL of messages received out of order. + */ + struct CadetReliableMessage *head_recv; + struct CadetReliableMessage *tail_recv; + + /** + * Messages received. + */ + unsigned int n_recv; + + /** + * Next MID to use for outgoing traffic. + */ + uint32_t mid_send; + + /** + * Next MID expected for incoming traffic. + */ + uint32_t mid_recv; + + /** + * Handle for queued unique data CREATE, DATA_ACK. + */ + struct CadetChannelQueue *uniq; + + /** + * Can we send data to the client? + */ + int client_ready; + + /** + * Can the client send data to us? + */ + int client_allowed; + + /** + * Task to resend/poll in case no ACK is received. + */ + GNUNET_SCHEDULER_TaskIdentifier retry_task; + + /** + * Counter for exponential backoff. + */ + struct GNUNET_TIME_Relative retry_timer; + + /** + * How long does it usually take to get an ACK. + */ + struct GNUNET_TIME_Relative expected_delay; +}; + + +/** + * Struct containing all information regarding a channel to a remote client. + */ +struct CadetChannel +{ + /** + * Tunnel this channel is in. + */ + struct CadetTunnel3 *t; + + /** + * Destination port of the channel. + */ + uint32_t port; + + /** + * Global channel number ( < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) + */ + CADET_ChannelNumber gid; + + /** + * Local tunnel number for root (owner) client. + * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI or 0 ) + */ + CADET_ChannelNumber lid_root; + + /** + * Local tunnel number for local destination clients (incoming number) + * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV or 0). + */ + CADET_ChannelNumber lid_dest; + + /** + * Channel state. + */ + enum CadetChannelState state; + + /** + * Is the tunnel bufferless (minimum latency)? + */ + int nobuffer; + + /** + * Is the tunnel reliable? + */ + int reliable; + + /** + * Last time the channel was used + */ + struct GNUNET_TIME_Absolute timestamp; + + /** + * Client owner of the tunnel, if any + */ + struct CadetClient *root; + + /** + * Client destination of the tunnel, if any. + */ + struct CadetClient *dest; + + /** + * Flag to signal the destruction of the channel. + * If this is set GNUNET_YES the channel will be destroyed + * when the queue is empty. + */ + int destroy; + + /** + * Total (reliable) messages pending ACK for this channel. + */ + unsigned int pending_messages; + + /** + * Reliability data. + * Only present (non-NULL) at the owner of a tunnel. + */ + struct CadetChannelReliability *root_rel; + + /** + * Reliability data. + * Only present (non-NULL) at the destination of a tunnel. + */ + struct CadetChannelReliability *dest_rel; + +}; + + +/******************************************************************************/ +/******************************* GLOBALS ***********************************/ +/******************************************************************************/ + +/** + * Global handle to the statistics service. + */ +extern struct GNUNET_STATISTICS_Handle *stats; + +/** + * Local peer own ID (memory efficient handle). + */ +extern GNUNET_PEER_Id myid; + + +/******************************************************************************/ +/******************************** STATIC ***********************************/ +/******************************************************************************/ + +/** + * Destroy a reliable message after it has been acknowledged, either by + * direct mid ACK or bitfield. Updates the appropriate data structures and + * timers and frees all memory. + * + * @param copy Message that is no longer needed: remote peer got it. + * @param update_time Is the timing information relevant? + * If this message is ACK in a batch the timing information + * is skewed by the retransmission, count only for the + * retransmitted message. + */ +static int +rel_message_free (struct CadetReliableMessage *copy, int update_time); + +/** + * send a channel create message. + * + * @param ch Channel for which to send. + */ +static void +send_create (struct CadetChannel *ch); + +/** + * Confirm we got a channel create, FWD ack. + * + * @param ch The channel to confirm. + * @param fwd Should we send a FWD ACK? (going dest->root) + * @param reaction This ACK is a reaction to a duplicate CREATE, don't save. + */ +static void +send_ack (struct CadetChannel *ch, int fwd, int reaction); + + + +/** + * Test if the channel is loopback: both root and dest are on the local peer. + * + * @param ch Channel to test. + * + * @return #GNUNET_YES if channel is loopback, #GNUNET_NO otherwise. + */ +static int +is_loopback (const struct CadetChannel *ch) +{ + if (NULL != ch->t) + return GMT_is_loopback (ch->t); + + return (NULL != ch->root && NULL != ch->dest); +} + + +/** + * Save a copy of the data message for later retransmission. + * + * @param msg Message to copy. + * @param mid Message ID. + * @param rel Reliability data for retransmission. + */ +static struct CadetReliableMessage * +copy_message (const struct GNUNET_CADET_Data *msg, uint32_t mid, + struct CadetChannelReliability *rel) +{ + struct CadetReliableMessage *copy; + uint16_t size; + + size = ntohs (msg->header.size); + copy = GNUNET_malloc (sizeof (*copy) + size); + copy->mid = mid; + copy->rel = rel; + copy->type = GNUNET_MESSAGE_TYPE_CADET_DATA; + memcpy (©[1], msg, size); + + return copy; +} + +/** + * We have received a message out of order, or the client is not ready. + * Buffer it until we receive an ACK from the client or the missing + * message from the channel. + * + * @param msg Message to buffer (MUST be of type CADET_DATA). + * @param rel Reliability data to the corresponding direction. + */ +static void +add_buffered_data (const struct GNUNET_CADET_Data *msg, + struct CadetChannelReliability *rel) +{ + struct CadetReliableMessage *copy; + struct CadetReliableMessage *prev; + uint32_t mid; + + mid = ntohl (msg->mid); + + LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data %u\n", mid); + + rel->n_recv++; + + // FIXME do something better than O(n), although n < 64... + // FIXME start from the end (most messages are the latest ones) + for (prev = rel->head_recv; NULL != prev; prev = prev->next) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " prev %u\n", prev->mid); + if (prev->mid == mid) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " already there!\n"); + return; + } + else if (GM_is_pid_bigger (prev->mid, mid)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " bingo!\n"); + copy = copy_message (msg, mid, rel); + GNUNET_CONTAINER_DLL_insert_before (rel->head_recv, rel->tail_recv, + prev, copy); + return; + } + } + copy = copy_message (msg, mid, rel); + LOG (GNUNET_ERROR_TYPE_DEBUG, " insert at tail!\n"); + GNUNET_CONTAINER_DLL_insert_tail (rel->head_recv, rel->tail_recv, copy); + LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data END\n"); +} + + +/** + * Add a destination client to a channel, initializing all data structures + * in the channel and the client. + * + * @param ch Channel to which add the destination. + * @param c Client which to add to the channel. + */ +static void +add_destination (struct CadetChannel *ch, struct CadetClient *c) +{ + if (NULL != ch->dest) + { + GNUNET_break (0); + return; + } + + /* Assign local id as destination */ + ch->lid_dest = GML_get_next_chid (c); + + /* Store in client's hashmap */ + GML_channel_add (c, ch->lid_dest, ch); + + GNUNET_break (NULL == ch->dest_rel); + ch->dest_rel = GNUNET_new (struct CadetChannelReliability); + ch->dest_rel->ch = ch; + ch->dest_rel->expected_delay.rel_value_us = 0; + ch->dest_rel->retry_timer = CADET_RETRANSMIT_TIME; + + ch->dest = c; +} + + +/** + * Set options in a channel, extracted from a bit flag field. + * + * @param ch Channel to set options to. + * @param options Bit array in host byte order. + */ +static void +channel_set_options (struct CadetChannel *ch, uint32_t options) +{ + ch->nobuffer = (options & GNUNET_CADET_OPTION_NOBUFFER) != 0 ? + GNUNET_YES : GNUNET_NO; + ch->reliable = (options & GNUNET_CADET_OPTION_RELIABLE) != 0 ? + GNUNET_YES : GNUNET_NO; +} + + +/** + * Get a bit flag field with the options of a channel. + * + * @param ch Channel to get options from. + * + * @return Bit array in host byte order. + */ +static uint32_t +channel_get_options (struct CadetChannel *ch) +{ + uint32_t options; + + options = 0; + if (ch->nobuffer) + options |= GNUNET_CADET_OPTION_NOBUFFER; + if (ch->reliable) + options |= GNUNET_CADET_OPTION_RELIABLE; + + return options; +} + + +/** + * Notify a client that the channel is no longer valid. + * + * @param ch Channel that is destroyed. + * @param local_only Should we avoid sending it to other peers? + */ +static void +send_destroy (struct CadetChannel *ch, int local_only) +{ + struct GNUNET_CADET_ChannelManage msg; + + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY); + msg.header.size = htons (sizeof (msg)); + msg.chid = htonl (ch->gid); + + /* If root is not NULL, notify. + * If it's NULL, check lid_root. When a local destroy comes in, root + * is set to NULL but lid_root is left untouched. In this case, do nothing, + * the client is the one who requested the channel to be destroyed. + */ + if (NULL != ch->root) + GML_send_channel_destroy (ch->root, ch->lid_root); + else if (0 == ch->lid_root && GNUNET_NO == local_only) + GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO, NULL); + + if (NULL != ch->dest) + GML_send_channel_destroy (ch->dest, ch->lid_dest); + else if (0 == ch->lid_dest && GNUNET_NO == local_only) + GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_YES, NULL); +} + + +/** + * Notify the destination client that a new incoming channel was created. + * + * @param ch Channel that was created. + */ +static void +send_client_create (struct CadetChannel *ch) +{ + uint32_t opt; + + if (NULL == ch->dest) + return; + + opt = 0; + opt |= GNUNET_YES == ch->reliable ? GNUNET_CADET_OPTION_RELIABLE : 0; + opt |= GNUNET_YES == ch->nobuffer ? GNUNET_CADET_OPTION_NOBUFFER : 0; + GML_send_channel_create (ch->dest, ch->lid_dest, ch->port, opt, + GMT_get_destination (ch->t)); + +} + + +/** + * Send data to a client. + * + * If the client is ready, send directly, otherwise buffer while listening + * for a local ACK. + * + * @param ch Channel + * @param msg Message. + * @param fwd Is this a fwd (root->dest) message? + */ +static void +send_client_data (struct CadetChannel *ch, + const struct GNUNET_CADET_Data *msg, + int fwd) +{ + if (fwd) + { + if (ch->dest_rel->client_ready) + GML_send_data (ch->dest, msg, ch->lid_dest); + else + add_buffered_data (msg, ch->dest_rel); + } + else + { + if (ch->root_rel->client_ready) + GML_send_data (ch->root, msg, ch->lid_root); + else + add_buffered_data (msg, ch->root_rel); + } +} + + +/** + * Send a buffered message to the client, for in order delivery or + * as result of client ACK. + * + * @param ch Channel on which to empty the message buffer. + * @param c Client to send to. + * @param fwd Is this to send FWD data?. + */ +static void +send_client_buffered_data (struct CadetChannel *ch, + struct CadetClient *c, + int fwd) +{ + struct CadetReliableMessage *copy; + struct CadetChannelReliability *rel; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data\n"); + rel = fwd ? ch->dest_rel : ch->root_rel; + if (GNUNET_NO == rel->client_ready) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "client not ready\n"); + return; + } + + copy = rel->head_recv; + /* We never buffer channel management messages */ + if (NULL != copy) + { + if (copy->mid == rel->mid_recv || GNUNET_NO == ch->reliable) + { + struct GNUNET_CADET_Data *msg = (struct GNUNET_CADET_Data *) ©[1]; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + " have %u! now expecting %u\n", + copy->mid, rel->mid_recv + 1); + send_client_data (ch, msg, fwd); + rel->n_recv--; + rel->mid_recv++; + GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy); + LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE RECV %p\n", copy); + GNUNET_free (copy); + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + " reliable && don't have %u, next is %u\n", + rel->mid_recv, + copy->mid); + if (GNUNET_YES == ch->destroy) + { + /* We don't have the next data piece and the remote peer has closed the + * channel. We won't receive it anymore, so just destroy the channel. + * FIXME: wait some time to allow other connections to + * deliver missing messages + */ + send_destroy (ch, GNUNET_YES); + GMCH_destroy (ch); + } + } + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data END\n"); +} + + +/** + * Allow a client to send more data. + * + * In case the client was already allowed to send data, do nothing. + * + * @param ch Channel. + * @param fwd Is this a FWD ACK? (FWD ACKs are sent to root) + */ +static void +send_client_ack (struct CadetChannel *ch, int fwd) +{ + struct CadetChannelReliability *rel = fwd ? ch->root_rel : ch->dest_rel; + struct CadetClient *c = fwd ? ch->root : ch->dest; + + if (NULL == c) + { + GNUNET_break (GNUNET_NO != ch->destroy); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + " sending %s ack to client on channel %s\n", + GM_f2s (fwd), GMCH_2s (ch)); + + if (NULL == rel) + { + GNUNET_break (0); + return; + } + + if (GNUNET_YES == rel->client_allowed) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " already allowed\n"); + return; + } + rel->client_allowed = GNUNET_YES; + + GML_send_ack (c, fwd ? ch->lid_root : ch->lid_dest); +} + + +/** + * Notify the root that the destination rejected the channel. + * + * @param ch Rejected channel. + */ +static void +send_client_nack (struct CadetChannel *ch) +{ + if (NULL == ch->root) + { + GNUNET_break (0); + return; + } + GML_send_channel_nack (ch->root, ch->lid_root); +} + + +/** + * We haven't received an ACK after a certain time: restransmit the message. + * + * @param cls Closure (CadetChannelReliability with the message to restransmit) + * @param tc TaskContext. + */ +static void +channel_retransmit_message (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CadetChannelReliability *rel = cls; + struct CadetReliableMessage *copy; + struct CadetChannel *ch; + struct GNUNET_CADET_Data *payload; + int fwd; + + rel->retry_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + + ch = rel->ch; + copy = rel->head_sent; + if (NULL == copy) + { + GNUNET_break (0); + return; + } + + payload = (struct GNUNET_CADET_Data *) ©[1]; + fwd = (rel == ch->root_rel); + + /* Message not found in the queue that we are going to use. */ + LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! RETRANSMIT %u\n", copy->mid); + + GMCH_send_prebuilt_message (&payload->header, ch, fwd, copy); + GNUNET_STATISTICS_update (stats, "# data retransmitted", 1, GNUNET_NO); +} + + +/** + * We haven't received an Channel ACK after a certain time: resend the CREATE. + * + * @param cls Closure (CadetChannelReliability of the channel to recreate) + * @param tc TaskContext. + */ +static void +channel_recreate (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CadetChannelReliability *rel = cls; + + rel->retry_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! RE-CREATE\n"); + GNUNET_STATISTICS_update (stats, "# data retransmitted", 1, GNUNET_NO); + + if (rel == rel->ch->root_rel) + { + send_create (rel->ch); + } + else if (rel == rel->ch->dest_rel) + { + send_ack (rel->ch, GNUNET_YES, GNUNET_NO); + } + else + { + GNUNET_break (0); + } + +} + + +/** + * Message has been sent: start retransmission timer. + * + * @param cls Closure (queue structure). + * @param t Tunnel. + * @param q Queue handler (no longer valid). + * @param type Type of message. + * @param size Size of the message. + */ +static void +ch_message_sent (void *cls, + struct CadetTunnel3 *t, + struct CadetTunnel3Queue *q, + uint16_t type, size_t size) +{ + struct CadetChannelQueue *chq = cls; + struct CadetReliableMessage *copy = chq->copy; + struct CadetChannelReliability *rel; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "channel message sent callback %s\n", + GM_m2s (chq->type)); + + switch (chq->type) + { + case GNUNET_MESSAGE_TYPE_CADET_DATA: + LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SENT DATA MID %u\n", copy->mid); + GNUNET_assert (chq == copy->chq); + copy->timestamp = GNUNET_TIME_absolute_get (); + rel = copy->rel; + if (GNUNET_SCHEDULER_NO_TASK == rel->retry_task) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "!! scheduling retry in 4 * %s\n", + GNUNET_STRINGS_relative_time_to_string (rel->expected_delay, + GNUNET_YES)); + if (0 != rel->expected_delay.rel_value_us) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "!! delay != 0\n"); + rel->retry_timer = + GNUNET_TIME_relative_multiply (rel->expected_delay, + CADET_RETRANSMIT_MARGIN); + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "!! delay reset\n"); + rel->retry_timer = CADET_RETRANSMIT_TIME; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "!! using delay %s\n", + GNUNET_STRINGS_relative_time_to_string (rel->retry_timer, + GNUNET_NO)); + rel->retry_task = + GNUNET_SCHEDULER_add_delayed (rel->retry_timer, + &channel_retransmit_message, rel); + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "!! retry task %u\n", rel->retry_task); + } + copy->chq = NULL; + break; + + + case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK: + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE: + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK: + LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SENT %s\n", GM_m2s (chq->type)); + rel = chq->rel; + GNUNET_assert (rel->uniq == chq); + rel->uniq = NULL; + + if (CADET_CHANNEL_READY != rel->ch->state + && GNUNET_MESSAGE_TYPE_CADET_DATA_ACK != type + && GNUNET_NO == rel->ch->destroy) + { + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == rel->retry_task); + LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! STD BACKOFF %s\n", + GNUNET_STRINGS_relative_time_to_string (rel->retry_timer, + GNUNET_NO)); + rel->retry_timer = GNUNET_TIME_STD_BACKOFF (rel->retry_timer); + rel->retry_task = GNUNET_SCHEDULER_add_delayed (rel->retry_timer, + &channel_recreate, rel); + } + break; + + default: + GNUNET_break (0); + } + + GNUNET_free (chq); +} + + +/** + * send a channel create message. + * + * @param ch Channel for which to send. + */ +static void +send_create (struct CadetChannel *ch) +{ + struct GNUNET_CADET_ChannelCreate msgcc; + + msgcc.header.size = htons (sizeof (msgcc)); + msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE); + msgcc.chid = htonl (ch->gid); + msgcc.port = htonl (ch->port); + msgcc.opt = htonl (channel_get_options (ch)); + + GMCH_send_prebuilt_message (&msgcc.header, ch, GNUNET_YES, NULL); +} + + +/** + * Confirm we got a channel create or FWD ack. + * + * @param ch The channel to confirm. + * @param fwd Should we send a FWD ACK? (going dest->root) + * @param reaction This ACK is a reaction to a duplicate CREATE, don't save. + */ +static void +send_ack (struct CadetChannel *ch, int fwd, int reaction) +{ + struct GNUNET_CADET_ChannelManage msg; + + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK); + LOG (GNUNET_ERROR_TYPE_DEBUG, " sending channel %s ack for channel %s\n", + GM_f2s (fwd), GMCH_2s (ch)); + + msg.chid = htonl (ch->gid); + GMCH_send_prebuilt_message (&msg.header, ch, !fwd, reaction ? &msg : NULL); +} + + +/** + * Send a message and don't keep any info about it: we won't need to cancel it + * or resend it. + * + * @param msg Header of the message to fire away. + * @param ch Channel on which the message should go. + * @param force Is this a forced (undroppable) message? + */ +static void +fire_and_forget (const struct GNUNET_MessageHeader *msg, + struct CadetChannel *ch, + int force) +{ + GNUNET_break (NULL == GMT_send_prebuilt_message (msg, ch->t, NULL, + force, NULL, NULL)); +} + + +/** + * Notify that a channel create didn't succeed. + * + * @param ch The channel to reject. + */ +static void +send_nack (struct CadetChannel *ch) +{ + struct GNUNET_CADET_ChannelManage msg; + + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK); + LOG (GNUNET_ERROR_TYPE_DEBUG, + " sending channel NACK for channel %s\n", + GMCH_2s (ch)); + + msg.chid = htonl (ch->gid); + GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO, NULL); +} + + +/** + * Destroy all reliable messages queued for a channel, + * during a channel destruction. + * Frees the reliability structure itself. + * + * @param rel Reliability data for a channel. + */ +static void +channel_rel_free_all (struct CadetChannelReliability *rel) +{ + struct CadetReliableMessage *copy; + struct CadetReliableMessage *next; + + if (NULL == rel) + return; + + for (copy = rel->head_recv; NULL != copy; copy = next) + { + next = copy->next; + GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy); + LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE BATCH RECV %p\n", copy); + GNUNET_break (NULL == copy->chq); + GNUNET_free (copy); + } + for (copy = rel->head_sent; NULL != copy; copy = next) + { + next = copy->next; + GNUNET_CONTAINER_DLL_remove (rel->head_sent, rel->tail_sent, copy); + LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE BATCH %p\n", copy); + if (NULL != copy->chq) + { + if (NULL != copy->chq->tq) + { + GMT_cancel (copy->chq->tq); + /* ch_message_sent will free copy->q */ + } + else + { + GNUNET_free (copy->chq); + GNUNET_break (0); + } + } + GNUNET_free (copy); + } + if (NULL != rel->uniq && NULL != rel->uniq->tq) + { + GMT_cancel (rel->uniq->tq); + /* ch_message_sent is called freeing uniq */ + } + if (GNUNET_SCHEDULER_NO_TASK != rel->retry_task) + { + GNUNET_SCHEDULER_cancel (rel->retry_task); + rel->retry_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free (rel); +} + + +/** + * Mark future messages as ACK'd. + * + * @param rel Reliability data. + * @param msg DataACK message with a bitfield of future ACK'd messages. + */ +static void +channel_rel_free_sent (struct CadetChannelReliability *rel, + const struct GNUNET_CADET_DataACK *msg) +{ + struct CadetReliableMessage *copy; + struct CadetReliableMessage *next; + uint64_t bitfield; + uint64_t mask; + uint32_t mid; + uint32_t target; + unsigned int i; + + bitfield = msg->futures; + mid = ntohl (msg->mid); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "!!! free_sent_reliable %u %llX\n", + mid, bitfield); + LOG (GNUNET_ERROR_TYPE_DEBUG, + " rel %p, head %p\n", + rel, rel->head_sent); + for (i = 0, copy = rel->head_sent; + i < 64 && NULL != copy && 0 != bitfield; + i++) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + " trying bit %u (mid %u)\n", + i, mid + i + 1); + mask = 0x1LL << i; + if (0 == (bitfield & mask)) + continue; + + LOG (GNUNET_ERROR_TYPE_DEBUG, " set!\n"); + /* Bit was set, clear the bit from the bitfield */ + bitfield &= ~mask; + + /* The i-th bit was set. Do we have that copy? */ + /* Skip copies with mid < target */ + target = mid + i + 1; + LOG (GNUNET_ERROR_TYPE_DEBUG, " target %u\n", target); + while (NULL != copy && GM_is_pid_bigger (target, copy->mid)) + copy = copy->next; + + /* Did we run out of copies? (previously freed, it's ok) */ + if (NULL == copy) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "run out of copies...\n"); + return; + } + + /* Did we overshoot the target? (previously freed, it's ok) */ + if (GM_is_pid_bigger (copy->mid, target)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " next copy %u\n", copy->mid); + continue; + } + + /* Now copy->mid == target, free it */ + next = copy->next; + GNUNET_break (GNUNET_YES != rel_message_free (copy, GNUNET_YES)); + copy = next; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "free_sent_reliable END\n"); +} + + +/** + * Destroy a reliable message after it has been acknowledged, either by + * direct mid ACK or bitfield. Updates the appropriate data structures and + * timers and frees all memory. + * + * @param copy Message that is no longer needed: remote peer got it. + * @param update_time Is the timing information relevant? + * If this message is ACK in a batch the timing information + * is skewed by the retransmission, count only for the + * retransmitted message. + * + * @return #GNUNET_YES if channel was destroyed as a result of the call, + * #GNUNET_NO otherwise. + */ +static int +rel_message_free (struct CadetReliableMessage *copy, int update_time) +{ + struct CadetChannelReliability *rel; + struct GNUNET_TIME_Relative time; + + rel = copy->rel; + LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Freeing %u\n", copy->mid); + if (update_time) + { + time = GNUNET_TIME_absolute_get_duration (copy->timestamp); + if (0 == rel->expected_delay.rel_value_us) + rel->expected_delay = time; + else + { + rel->expected_delay.rel_value_us *= 7; + rel->expected_delay.rel_value_us += time.rel_value_us; + rel->expected_delay.rel_value_us /= 8; + } + LOG (GNUNET_ERROR_TYPE_INFO, "!!! took %s, new delay %s\n", + GNUNET_STRINGS_relative_time_to_string (time, GNUNET_NO), + GNUNET_STRINGS_relative_time_to_string (rel->expected_delay, + GNUNET_NO)); + rel->retry_timer = rel->expected_delay; + } + else + { + LOG (GNUNET_ERROR_TYPE_INFO, "!!! batch free, ignoring timing\n"); + } + rel->ch->pending_messages--; + if (NULL != copy->chq) + { + GMT_cancel (copy->chq->tq); + /* copy->q is set to NULL by ch_message_sent */ + } + GNUNET_CONTAINER_DLL_remove (rel->head_sent, rel->tail_sent, copy); + LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE %p\n", copy); + GNUNET_free (copy); + + if (GNUNET_NO != rel->ch->destroy && 0 == rel->ch->pending_messages) + { + GMCH_destroy (rel->ch); + return GNUNET_YES; + } + return GNUNET_NO; +} + + +/** + * Channel was ACK'd by remote peer, mark as ready and cancel retransmission. + * + * @param ch Channel to mark as ready. + * @param fwd Was the ACK message a FWD ACK? (dest->root, SYNACK) + */ +static void +channel_confirm (struct CadetChannel *ch, int fwd) +{ + struct CadetChannelReliability *rel; + enum CadetChannelState oldstate; + + rel = fwd ? ch->root_rel : ch->dest_rel; + if (NULL == rel) + { + GNUNET_break (GNUNET_NO != ch->destroy); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " channel confirm %s %s\n", + GM_f2s (fwd), GMCH_2s (ch)); + oldstate = ch->state; + ch->state = CADET_CHANNEL_READY; + + if (CADET_CHANNEL_READY != oldstate || GNUNET_YES == is_loopback (ch)) + { + rel->client_ready = GNUNET_YES; + rel->expected_delay = rel->retry_timer; + LOG (GNUNET_ERROR_TYPE_DEBUG, " !! retry timer confirm %s\n", + GNUNET_STRINGS_relative_time_to_string (rel->retry_timer, GNUNET_NO)); + if (GMT_get_connections_buffer (ch->t) > 0 || GMT_is_loopback (ch->t)) + send_client_ack (ch, fwd); + + if (GNUNET_SCHEDULER_NO_TASK != rel->retry_task) + { + GNUNET_SCHEDULER_cancel (rel->retry_task); + rel->retry_task = GNUNET_SCHEDULER_NO_TASK; + } + else if (NULL != rel->uniq) + { + GMT_cancel (rel->uniq->tq); + /* ch_message_sent will free and NULL uniq */ + } + else + { + if (GNUNET_NO == is_loopback (ch)) + { + /* We SHOULD have been trying to retransmit this! */ + GNUNET_break (0); + } + } + } + + /* In case of a FWD ACK (SYNACK) send a BCK ACK (ACK). */ + if (GNUNET_YES == fwd) + send_ack (ch, GNUNET_NO, GNUNET_NO); +} + + +/** + * Save a copy to retransmit in case it gets lost. + * + * Initializes all needed callbacks and timers. + * + * @param ch Channel this message goes on. + * @param msg Message to copy. + * @param fwd Is this fwd traffic? + */ +static struct CadetReliableMessage * +channel_save_copy (struct CadetChannel *ch, + const struct GNUNET_MessageHeader *msg, + int fwd) +{ + struct CadetChannelReliability *rel; + struct CadetReliableMessage *copy; + uint32_t mid; + uint16_t type; + uint16_t size; + + rel = fwd ? ch->root_rel : ch->dest_rel; + mid = rel->mid_send - 1; + type = ntohs (msg->type); + size = ntohs (msg->size); + + LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SAVE %u %s\n", mid, GM_m2s (type)); + copy = GNUNET_malloc (sizeof (struct CadetReliableMessage) + size); + LOG (GNUNET_ERROR_TYPE_DEBUG, " at %p\n", copy); + copy->mid = mid; + copy->rel = rel; + copy->type = type; + memcpy (©[1], msg, size); + GNUNET_CONTAINER_DLL_insert_tail (rel->head_sent, rel->tail_sent, copy); + ch->pending_messages++; + + return copy; +} + + +/** + * Create a new channel. + * + * @param t Tunnel this channel is in. + * @param owner Client that owns the channel, NULL for foreign channels. + * @param lid_root Local ID for root client. + * + * @return A new initialized channel. NULL on error. + */ +static struct CadetChannel * +channel_new (struct CadetTunnel3 *t, + struct CadetClient *owner, + CADET_ChannelNumber lid_root) +{ + struct CadetChannel *ch; + + ch = GNUNET_new (struct CadetChannel); + ch->root = owner; + ch->lid_root = lid_root; + ch->t = t; + + GNUNET_STATISTICS_update (stats, "# channels", 1, GNUNET_NO); + + if (NULL != owner) + { + ch->gid = GMT_get_next_chid (t); + GML_channel_add (owner, lid_root, ch); + } + GMT_add_channel (t, ch); + + return ch; +} + + +/** + * Handle a loopback message: call the appropriate handler for the message type. + * + * @param ch Channel this message is on. + * @param msgh Message header. + * @param fwd Is this FWD traffic? + */ +void +handle_loopback (struct CadetChannel *ch, + const struct GNUNET_MessageHeader *msgh, + int fwd) +{ + uint16_t type; + + type = ntohs (msgh->type); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Loopback %s %s message!\n", + GM_f2s (fwd), GM_m2s (type)); + + switch (type) + { + case GNUNET_MESSAGE_TYPE_CADET_DATA: + /* Don't send hop ACK, wait for client to ACK */ + LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SEND loopback %u (%u)\n", + ntohl (((struct GNUNET_CADET_Data *) msgh)->mid), ntohs (msgh->size)); + GMCH_handle_data (ch, (struct GNUNET_CADET_Data *) msgh, fwd); + break; + + case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK: + GMCH_handle_data_ack (ch, (struct GNUNET_CADET_DataACK *) msgh, fwd); + break; + + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE: + GMCH_handle_create (ch->t, + (struct GNUNET_CADET_ChannelCreate *) msgh); + break; + + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK: + GMCH_handle_ack (ch, + (struct GNUNET_CADET_ChannelManage *) msgh, + fwd); + break; + + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK: + GMCH_handle_nack (ch); + break; + + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: + GMCH_handle_destroy (ch, + (struct GNUNET_CADET_ChannelManage *) msgh, + fwd); + break; + + default: + GNUNET_break_op (0); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "end-to-end message not known (%u)\n", + ntohs (msgh->type)); + } +} + + + +/******************************************************************************/ +/******************************** API ***********************************/ +/******************************************************************************/ + +/** + * Destroy a channel and free all resources. + * + * @param ch Channel to destroy. + */ +void +GMCH_destroy (struct CadetChannel *ch) +{ + struct CadetClient *c; + struct CadetTunnel3 *t; + + if (NULL == ch) + return; + if (2 == ch->destroy) + return; /* recursive call */ + ch->destroy = 2; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying channel %s:%u\n", + GMT_2s (ch->t), ch->gid); + GMCH_debug (ch); + + c = ch->root; + if (NULL != c) + { + GML_channel_remove (c, ch->lid_root, ch); + } + + c = ch->dest; + if (NULL != c) + { + GML_channel_remove (c, ch->lid_dest, ch); + } + + channel_rel_free_all (ch->root_rel); + channel_rel_free_all (ch->dest_rel); + + t = ch->t; + GMT_remove_channel (t, ch); + GNUNET_STATISTICS_update (stats, "# channels", -1, GNUNET_NO); + + GNUNET_free (ch); + GMT_destroy_if_empty (t); +} + + +/** + * Get the channel's public ID. + * + * @param ch Channel. + * + * @return ID used to identify the channel with the remote peer. + */ +CADET_ChannelNumber +GMCH_get_id (const struct CadetChannel *ch) +{ + return ch->gid; +} + + +/** + * Get the channel tunnel. + * + * @param ch Channel to get the tunnel from. + * + * @return tunnel of the channel. + */ +struct CadetTunnel3 * +GMCH_get_tunnel (const struct CadetChannel *ch) +{ + return ch->t; +} + + +/** + * Get free buffer space towards the client on a specific channel. + * + * @param ch Channel. + * @param fwd Is query about FWD traffic? + * + * @return Free buffer space [0 - 64] + */ +unsigned int +GMCH_get_buffer (struct CadetChannel *ch, int fwd) +{ + struct CadetChannelReliability *rel; + + rel = fwd ? ch->dest_rel : ch->root_rel; + + /* If rel is NULL it means that the end is not yet created, + * most probably is a loopback channel at the point of sending + * the ChannelCreate to itself. + */ + if (NULL == rel) + return 64; + + return (64 - rel->n_recv); +} + + +/** + * Get flow control status of end point: is client allow to send? + * + * @param ch Channel. + * @param fwd Is query about FWD traffic? (Request root status). + * + * @return #GNUNET_YES if client is allowed to send us data. + */ +int +GMCH_get_allowed (struct CadetChannel *ch, int fwd) +{ + struct CadetChannelReliability *rel; + + rel = fwd ? ch->root_rel : ch->dest_rel; + + if (NULL == rel) + { + /* Probably shutting down: root/dest NULL'ed to mark disconnection */ + GNUNET_break (GNUNET_NO != ch->destroy); + return 0; + } + + return rel->client_allowed; +} + + +/** + * Is the root client for this channel on this peer? + * + * @param ch Channel. + * @param fwd Is this for fwd traffic? + * + * @return #GNUNET_YES in case it is. + */ +int +GMCH_is_origin (struct CadetChannel *ch, int fwd) +{ + struct CadetClient *c; + + c = fwd ? ch->root : ch->dest; + return NULL != c; +} + + +/** + * Is the destination client for this channel on this peer? + * + * @param ch Channel. + * @param fwd Is this for fwd traffic? + * + * @return #GNUNET_YES in case it is. + */ +int +GMCH_is_terminal (struct CadetChannel *ch, int fwd) +{ + struct CadetClient *c; + + c = fwd ? ch->dest : ch->root; + return NULL != c; +} + + +/** + * Send an end-to-end ACK message for the most recent in-sequence payload. + * + * If channel is not reliable, do nothing. + * + * @param ch Channel this is about. + * @param fwd Is for FWD traffic? (ACK dest->owner) + */ +void +GMCH_send_data_ack (struct CadetChannel *ch, int fwd) +{ + struct GNUNET_CADET_DataACK msg; + struct CadetChannelReliability *rel; + struct CadetReliableMessage *copy; + unsigned int delta; + uint64_t mask; + uint32_t ack; + + if (GNUNET_NO == ch->reliable) + { + return; + } + rel = fwd ? ch->dest_rel : ch->root_rel; + ack = rel->mid_recv - 1; + LOG (GNUNET_ERROR_TYPE_INFO, "===> DATA_ACK for %u\n", ack); + + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_DATA_ACK); + msg.header.size = htons (sizeof (msg)); + msg.chid = htonl (ch->gid); + msg.futures = 0; + for (copy = rel->head_recv; NULL != copy; copy = copy->next) + { + if (copy->type != GNUNET_MESSAGE_TYPE_CADET_DATA) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "!! Type %s, expected DATA\n", + GM_m2s (copy->type)); + continue; + } + if (copy->mid == ack + 1) + { + ack++; + continue; + } + delta = copy->mid - (ack + 1); + if (63 < delta) + break; + mask = 0x1LL << delta; + msg.futures |= mask; + LOG (GNUNET_ERROR_TYPE_DEBUG, + " !! setting bit for %u (delta %u) (%llX) -> %llX\n", + copy->mid, delta, mask, msg.futures); + } + msg.mid = htonl (ack); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "!!! ACK for %u, futures %llX\n", + ack, msg.futures); + + GMCH_send_prebuilt_message (&msg.header, ch, !fwd, NULL); + LOG (GNUNET_ERROR_TYPE_DEBUG, "send_data_ack END\n"); +} + + +/** + * Allow a client to send us more data, in case it was choked. + * + * @param ch Channel. + * @param fwd Is this about FWD traffic? (Root client). + */ +void +GMCH_allow_client (struct CadetChannel *ch, int fwd) +{ + struct CadetChannelReliability *rel; + unsigned int buffer; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "GMCH allow\n"); + + if (CADET_CHANNEL_READY != ch->state) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " channel not ready yet!\n"); + return; + } + + if (GNUNET_YES == ch->reliable) + { + rel = fwd ? ch->root_rel : ch->dest_rel; + if (NULL == rel) + { + GNUNET_break (GNUNET_NO != ch->destroy); + return; + } + if (NULL != rel->head_sent) + { + if (64 <= rel->mid_send - rel->head_sent->mid) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " too big MID gap! Wait for ACK.\n"); + return; + } + else + LOG (GNUNET_ERROR_TYPE_DEBUG, " gap ok: %u - %u\n", + rel->head_sent->mid, rel->mid_send); + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " head sent is NULL\n"); + } + } + + if (is_loopback (ch)) + buffer = GMCH_get_buffer (ch, fwd); + else + buffer = GMT_get_connections_buffer (ch->t); + + if (0 == buffer) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " no buffer space.\n"); + return; + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space %u, allowing\n", buffer); + send_client_ack (ch, fwd); +} + + +/** + * Log channel info. + * + * @param ch Channel. + */ +void +GMCH_debug (struct CadetChannel *ch) +{ + if (NULL == ch) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "*** DEBUG NULL CHANNEL ***\n"); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %s:%X (%p)\n", + GMT_2s (ch->t), ch->gid, ch); + LOG (GNUNET_ERROR_TYPE_DEBUG, " root %p/%p\n", + ch->root, ch->root_rel); + if (NULL != ch->root) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " cli %s\n", GML_2s (ch->root)); + LOG (GNUNET_ERROR_TYPE_DEBUG, " ready %s\n", + ch->root_rel->client_ready ? "YES" : "NO"); + LOG (GNUNET_ERROR_TYPE_DEBUG, " id %X\n", ch->lid_root); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " dest %p/%p\n", + ch->dest, ch->dest_rel); + if (NULL != ch->dest) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " cli %s\n", GML_2s (ch->dest)); + LOG (GNUNET_ERROR_TYPE_DEBUG, " ready %s\n", + ch->dest_rel->client_ready ? "YES" : "NO"); + LOG (GNUNET_ERROR_TYPE_DEBUG, " id %X\n", ch->lid_dest); + } +} + + +/** + * Handle an ACK given by a client. + * + * Mark client as ready and send him any buffered data we could have for him. + * + * @param ch Channel. + * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by dest and go BCK) + */ +void +GMCH_handle_local_ack (struct CadetChannel *ch, int fwd) +{ + struct CadetChannelReliability *rel; + struct CadetClient *c; + + rel = fwd ? ch->dest_rel : ch->root_rel; + c = fwd ? ch->dest : ch->root; + + rel->client_ready = GNUNET_YES; + send_client_buffered_data (ch, c, fwd); + + if (GNUNET_YES == ch->destroy && 0 == rel->n_recv) + { + send_destroy (ch, GNUNET_YES); + GMCH_destroy (ch); + } + /* if loopback is marked for destruction, no need to ACK to the other peer, + * it requested the destruction and is already gone, therefore, else if. + */ + else if (is_loopback (ch)) + { + unsigned int buffer; + + buffer = GMCH_get_buffer (ch, fwd); + if (0 < buffer) + GMCH_allow_client (ch, fwd); + + return; + } + GMT_send_connection_acks (ch->t); +} + + +/** + * Handle data given by a client. + * + * Check whether the client is allowed to send in this tunnel, save if channel + * is reliable and send an ACK to the client if there is still buffer space + * in the tunnel. + * + * @param ch Channel. + * @param c Client which sent the data. + * @param message Message. + * @param fwd Is this a FWD data? + * + * @return GNUNET_OK if everything goes well, GNUNET_SYSERR in case of en error. + */ +int +GMCH_handle_local_data (struct CadetChannel *ch, + struct CadetClient *c, + struct GNUNET_MessageHeader *message, + int fwd) +{ + struct CadetChannelReliability *rel; + struct GNUNET_CADET_Data *payload; + size_t size = ntohs (message->size); + uint16_t p2p_size = sizeof(struct GNUNET_CADET_Data) + size; + unsigned char cbuf[p2p_size]; + + /* Is the client in the channel? */ + if ( !( (fwd && + ch->root == c) + || + (!fwd && + ch->dest == c) ) ) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + rel = fwd ? ch->root_rel : ch->dest_rel; + + if (GNUNET_NO == rel->client_allowed) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + rel->client_allowed = GNUNET_NO; + + /* Ok, everything is correct, send the message. */ + payload = (struct GNUNET_CADET_Data *) cbuf; + payload->mid = htonl (rel->mid_send); + rel->mid_send++; + memcpy (&payload[1], message, size); + payload->header.size = htons (p2p_size); + payload->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_DATA); + payload->chid = htonl (ch->gid); + LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channel...\n"); + GMCH_send_prebuilt_message (&payload->header, ch, fwd, NULL); + + if (is_loopback (ch)) + { + if (GMCH_get_buffer (ch, fwd) > 0) + GMCH_allow_client (ch, fwd); + + return GNUNET_OK; + } + + if (GMT_get_connections_buffer (ch->t) > 0) + { + GMCH_allow_client (ch, fwd); + } + + return GNUNET_OK; +} + + +/** + * Handle a channel destroy requested by a client. + * + * Destroy the channel and the tunnel in case this was the last channel. + * + * @param ch Channel. + * @param c Client that requested the destruction (to avoid notifying him). + * @param is_root Is the request coming from root? + */ +void +GMCH_handle_local_destroy (struct CadetChannel *ch, + struct CadetClient *c, + int is_root) +{ + ch->destroy = GNUNET_YES; + /* Cleanup after the tunnel */ + if (GNUNET_NO == is_root && c == ch->dest) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is destination.\n", GML_2s (c)); + GML_client_delete_channel (c, ch, ch->lid_dest); + ch->dest = NULL; + } + if (GNUNET_YES == is_root && c == ch->root) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is owner.\n", GML_2s (c)); + GML_client_delete_channel (c, ch, ch->lid_root); + ch->root = NULL; + } + + send_destroy (ch, GNUNET_NO); + if (0 == ch->pending_messages) + GMCH_destroy (ch); +} + + +/** + * Handle a channel create requested by a client. + * + * Create the channel and the tunnel in case this was the first0 channel. + * + * @param c Client that requested the creation (will be the root). + * @param msg Create Channel message. + * + * @return GNUNET_OK if everything went fine, GNUNET_SYSERR otherwise. + */ +int +GMCH_handle_local_create (struct CadetClient *c, + struct GNUNET_CADET_ChannelMessage *msg) +{ + struct CadetChannel *ch; + struct CadetTunnel3 *t; + struct CadetPeer *peer; + CADET_ChannelNumber chid; + + LOG (GNUNET_ERROR_TYPE_DEBUG, " towards %s:%u\n", + GNUNET_i2s (&msg->peer), ntohl (msg->port)); + chid = ntohl (msg->channel_id); + + /* Sanity check for duplicate channel IDs */ + if (NULL != GML_channel_get (c, chid)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + peer = GMP_get (&msg->peer); + GMP_add_tunnel (peer); + t = GMP_get_tunnel (peer); + + if (GMP_get_short_id (peer) == myid) + { + GMT_change_cstate (t, CADET_TUNNEL3_READY); + } + else + { + /* FIXME change to a tunnel API, eliminate ch <-> peer connection */ + GMP_connect (peer); + } + + /* Create channel */ + ch = channel_new (t, c, chid); + if (NULL == ch) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + ch->port = ntohl (msg->port); + channel_set_options (ch, ntohl (msg->opt)); + + /* In unreliable channels, we'll use the DLL to buffer BCK data */ + ch->root_rel = GNUNET_new (struct CadetChannelReliability); + ch->root_rel->ch = ch; + ch->root_rel->retry_timer = CADET_RETRANSMIT_TIME; + ch->root_rel->expected_delay.rel_value_us = 0; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "CREATED CHANNEL %s\n", GMCH_2s (ch)); + + send_create (ch); + + return GNUNET_OK; +} + + +/** + * Handler for cadet network payload traffic. + * + * @param ch Channel for the message. + * @param msg Unencryted data message. + * @param fwd Is this message fwd? This only is meaningful in loopback channels. + * #GNUNET_YES if message is FWD on the respective channel (loopback) + * #GNUNET_NO if message is BCK on the respective channel (loopback) + * #GNUNET_SYSERR if message on a one-ended channel (remote) + */ +void +GMCH_handle_data (struct CadetChannel *ch, + const struct GNUNET_CADET_Data *msg, + int fwd) +{ + struct CadetChannelReliability *rel; + struct CadetClient *c; + uint32_t mid; + + /* If this is a remote (non-loopback) channel, find 'fwd'. */ + if (GNUNET_SYSERR == fwd) + { + if (is_loopback (ch)) + { + /* It is a loopback channel after all... */ + GNUNET_break (0); + return; + } + fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO; + } + + /* Initialize FWD/BCK data */ + c = fwd ? ch->dest : ch->root; + rel = fwd ? ch->dest_rel : ch->root_rel; + + if (NULL == c) + { + GNUNET_break (GNUNET_NO != ch->destroy); + return; + } + + if (CADET_CHANNEL_READY != ch->state) + { + if (GNUNET_NO == fwd) + { + /* If we are the root, this means the other peer has sent traffic before + * receiving our ACK. Even if the SYNACK goes missing, no traffic should + * be sent before the ACK. + */ + GNUNET_break_op (0); + return; + } + /* If we are the dest, this means that the SYNACK got to the root but + * the ACK went missing. Treat this as an ACK. + */ + channel_confirm (ch, GNUNET_NO); + } + + GNUNET_STATISTICS_update (stats, "# data received", 1, GNUNET_NO); + + mid = ntohl (msg->mid); + LOG (GNUNET_ERROR_TYPE_INFO, "<=== DATA %u %s on channel %s\n", + mid, GM_f2s (fwd), GMCH_2s (ch)); + + if (GNUNET_NO == ch->reliable || + ( !GM_is_pid_bigger (rel->mid_recv, mid) && + GM_is_pid_bigger (rel->mid_recv + 64, mid) ) ) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "RECV %u (%u)\n", + mid, ntohs (msg->header.size)); + if (GNUNET_YES == ch->reliable) + { + /* Is this the exact next expected messasge? */ + if (mid == rel->mid_recv) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "as expected\n"); + rel->mid_recv++; + send_client_data (ch, msg, fwd); + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "save for later\n"); + add_buffered_data (msg, rel); + } + } + else + { + /* Tunnel is unreliable: send to clients directly */ + /* FIXME: accept Out Of Order traffic */ + rel->mid_recv = mid + 1; + send_client_data (ch, msg, fwd); + } + } + else + { + GNUNET_break_op (GM_is_pid_bigger (rel->mid_recv, mid)); + LOG (GNUNET_ERROR_TYPE_WARNING, + "MID %u not expected (%u - %u), dropping!\n", + mid, rel->mid_recv, rel->mid_recv + 63); + } + + GMCH_send_data_ack (ch, fwd); +} + + +/** + * Handler for cadet network traffic end-to-end ACKs. + * + * @param ch Channel on which we got this message. + * @param msg Data message. + * @param fwd Is this message fwd? This only is meaningful in loopback channels. + * #GNUNET_YES if message is FWD on the respective channel (loopback) + * #GNUNET_NO if message is BCK on the respective channel (loopback) + * #GNUNET_SYSERR if message on a one-ended channel (remote) + */ +void +GMCH_handle_data_ack (struct CadetChannel *ch, + const struct GNUNET_CADET_DataACK *msg, + int fwd) +{ + struct CadetChannelReliability *rel; + struct CadetReliableMessage *copy; + struct CadetReliableMessage *next; + uint32_t ack; + int work; + + /* If this is a remote (non-loopback) channel, find 'fwd'. */ + if (GNUNET_SYSERR == fwd) + { + if (is_loopback (ch)) + { + /* It is a loopback channel after all... */ + GNUNET_break (0); + return; + } + /* Inverted: if message came 'FWD' is a 'BCK ACK'. */ + fwd = (NULL != ch->dest) ? GNUNET_NO : GNUNET_YES; + } + + ack = ntohl (msg->mid); + LOG (GNUNET_ERROR_TYPE_INFO, "<=== %s ACK %u\n", GM_f2s (fwd), ack); + + if (GNUNET_YES == fwd) + { + rel = ch->root_rel; + } + else + { + rel = ch->dest_rel; + } + if (NULL == rel) + { + GNUNET_break_op (GNUNET_NO != ch->destroy); + return; + } + + /* Free ACK'd copies: no need to retransmit those anymore FIXME refactor */ + for (work = GNUNET_NO, copy = rel->head_sent; copy != NULL; copy = next) + { + if (GM_is_pid_bigger (copy->mid, ack)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " head %u, out!\n", copy->mid); + channel_rel_free_sent (rel, msg); + break; + } + work = GNUNET_YES; + LOG (GNUNET_ERROR_TYPE_DEBUG, " id %u\n", copy->mid); + next = copy->next; + if (GNUNET_YES == rel_message_free (copy, GNUNET_YES)) + return; + } + + /* ACK client if needed and possible */ + GMCH_allow_client (ch, fwd); + + /* If some message was free'd, update the retransmission delay */ + if (GNUNET_YES == work) + { + if (GNUNET_SCHEDULER_NO_TASK != rel->retry_task) + { + GNUNET_SCHEDULER_cancel (rel->retry_task); + rel->retry_task = GNUNET_SCHEDULER_NO_TASK; + if (NULL != rel->head_sent && NULL == rel->head_sent->chq) + { + struct GNUNET_TIME_Absolute new_target; + struct GNUNET_TIME_Relative delay; + + delay = GNUNET_TIME_relative_multiply (rel->retry_timer, + CADET_RETRANSMIT_MARGIN); + new_target = GNUNET_TIME_absolute_add (rel->head_sent->timestamp, + delay); + delay = GNUNET_TIME_absolute_get_remaining (new_target); + rel->retry_task = + GNUNET_SCHEDULER_add_delayed (delay, + &channel_retransmit_message, + rel); + } + } + else + { + /* Work was done but no task was pending? Shouldn't happen! */ + GNUNET_break (0); + } + } +} + + +/** + * Handler for channel create messages. + * + * Does not have fwd parameter because it's always 'FWD': channel is incoming. + * + * @param t Tunnel this channel will be in. + * @param msg Channel crate message. + */ +struct CadetChannel * +GMCH_handle_create (struct CadetTunnel3 *t, + const struct GNUNET_CADET_ChannelCreate *msg) +{ + CADET_ChannelNumber chid; + struct CadetChannel *ch; + struct CadetClient *c; + int new_channel; + int reaction; + + reaction = GNUNET_NO; + chid = ntohl (msg->chid); + ch = GMT_get_channel (t, chid); + if (NULL == ch) + { + /* Create channel */ + ch = channel_new (t, NULL, 0); + ch->gid = chid; + channel_set_options (ch, ntohl (msg->opt)); + new_channel = GNUNET_YES; + } + else + { + new_channel = GNUNET_NO; + } + + if (GNUNET_YES == new_channel || GMT_is_loopback (t)) + { + /* Find a destination client */ + ch->port = ntohl (msg->port); + LOG (GNUNET_ERROR_TYPE_DEBUG, " port %u\n", ch->port); + c = GML_client_get_by_port (ch->port); + if (NULL == c) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " no client has port registered\n"); + if (is_loopback (ch)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " loopback: destroy on handler\n"); + send_nack (ch); + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " not loopback: destroy now\n"); + send_nack (ch); + GMCH_destroy (ch); + } + return NULL; + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " client %p has port registered\n", c); + } + + add_destination (ch, c); + if (GNUNET_YES == ch->reliable) + LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Reliable\n"); + else + LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Not Reliable\n"); + + send_client_create (ch); + ch->state = CADET_CHANNEL_SENT; + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate create channel\n"); + reaction = GNUNET_YES; + if (GNUNET_SCHEDULER_NO_TASK != ch->dest_rel->retry_task) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " clearing retry task\n"); + /* we were waiting to re-send our 'SYNACK', wait no more! */ + GNUNET_SCHEDULER_cancel (ch->dest_rel->retry_task); + ch->dest_rel->retry_task = GNUNET_SCHEDULER_NO_TASK; + } + } + send_ack (ch, GNUNET_YES, reaction); + + return ch; +} + + +/** + * Handler for channel NACK messages. + * + * NACK messages always go dest -> root, no need for 'fwd' or 'msg' parameter. + * + * @param ch Channel. + */ +void +GMCH_handle_nack (struct CadetChannel *ch) +{ + send_client_nack (ch); + GMCH_destroy (ch); +} + + +/** + * Handler for channel ack messages. + * + * @param ch Channel. + * @param msg Message. + * @param fwd Is this message fwd? This only is meaningful in loopback channels. + * #GNUNET_YES if message is FWD on the respective channel (loopback) + * #GNUNET_NO if message is BCK on the respective channel (loopback) + * #GNUNET_SYSERR if message on a one-ended channel (remote) + */ +void +GMCH_handle_ack (struct CadetChannel *ch, + const struct GNUNET_CADET_ChannelManage *msg, + int fwd) +{ + /* If this is a remote (non-loopback) channel, find 'fwd'. */ + if (GNUNET_SYSERR == fwd) + { + if (is_loopback (ch)) + { + /* It is a loopback channel after all... */ + GNUNET_break (0); + return; + } + fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO; + } + + channel_confirm (ch, !fwd); +} + + +/** + * Handler for channel destroy messages. + * + * @param ch Channel to be destroyed of. + * @param msg Message. + * @param fwd Is this message fwd? This only is meaningful in loopback channels. + * #GNUNET_YES if message is FWD on the respective channel (loopback) + * #GNUNET_NO if message is BCK on the respective channel (loopback) + * #GNUNET_SYSERR if message on a one-ended channel (remote) + */ +void +GMCH_handle_destroy (struct CadetChannel *ch, + const struct GNUNET_CADET_ChannelManage *msg, + int fwd) +{ + struct CadetChannelReliability *rel; + + /* If this is a remote (non-loopback) channel, find 'fwd'. */ + if (GNUNET_SYSERR == fwd) + { + if (is_loopback (ch)) + { + /* It is a loopback channel after all... */ + GNUNET_break (0); + return; + } + fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO; + } + + GMCH_debug (ch); + if ( (fwd && NULL == ch->dest) || (!fwd && NULL == ch->root) ) + { + /* Not for us (don't destroy twice a half-open loopback channel) */ + return; + } + + rel = fwd ? ch->dest_rel : ch->root_rel; + if (0 == rel->n_recv) + { + send_destroy (ch, GNUNET_YES); + GMCH_destroy (ch); + } + else + { + ch->destroy = GNUNET_YES; + } +} + + +/** + * Sends an already built message on a channel. + * + * If the channel is on a loopback tunnel, notifies the appropriate destination + * client locally. + * + * On a normal channel passes the message to the tunnel for encryption and + * sending on a connection. + * + * This function DOES NOT save the message for retransmission. + * + * @param message Message to send. Function makes a copy of it. + * @param ch Channel on which this message is transmitted. + * @param fwd Is this a fwd message? + * @param existing_copy This is a retransmission, don't save a copy. + */ +void +GMCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message, + struct CadetChannel *ch, int fwd, + void *existing_copy) +{ + struct CadetChannelQueue *chq; + uint16_t type; + + type = ntohs (message->type); + LOG (GNUNET_ERROR_TYPE_INFO, "===> %s %s on channel %s\n", + GM_m2s (type), GM_f2s (fwd), GMCH_2s (ch)); + + if (GMT_is_loopback (ch->t)) + { + handle_loopback (ch, message, fwd); + return; + } + + switch (type) + { + struct GNUNET_CADET_Data *payload; + case GNUNET_MESSAGE_TYPE_CADET_DATA: + + payload = (struct GNUNET_CADET_Data *) message; + LOG (GNUNET_ERROR_TYPE_INFO, "===> %s %u\n", + GM_m2s (type), ntohl (payload->mid)); + if (GNUNET_YES == ch->reliable) + { + chq = GNUNET_new (struct CadetChannelQueue); + chq->type = type; + if (NULL == existing_copy) + chq->copy = channel_save_copy (ch, message, fwd); + else + { + chq->copy = (struct CadetReliableMessage *) existing_copy; + if (NULL != chq->copy->chq) + { + /* Last retransmission was queued but not yet sent! + * This retransmission was scheduled by a ch_message_sent which + * followed a very fast RTT, so the tiny delay made the + * retransmission function to execute before the previous + * retransmitted message even had a chance to leave the peer. + * Cancel this message and wait until the pending + * retransmission leaves the peer and ch_message_sent starts + * the timer for the next one. + */ + GNUNET_free (chq); + LOG (GNUNET_ERROR_TYPE_DEBUG, + " exisitng copy not yet transmitted!\n"); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + " using existing copy: %p {r:%p q:%p t:%u}\n", + existing_copy, + chq->copy->rel, chq->copy->chq, chq->copy->type); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " new chq: %p\n", chq); + chq->copy->chq = chq; + chq->tq = GMT_send_prebuilt_message (message, ch->t, NULL, + NULL != existing_copy, + &ch_message_sent, chq); + /* q itself is stored in copy */ + GNUNET_assert (NULL != chq->tq || GNUNET_NO != ch->destroy); + } + else + { + fire_and_forget (message, ch, GNUNET_NO); + } + break; + + + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK: + if (GNUNET_YES == fwd || NULL != existing_copy) + { + /* BCK ACK (going FWD) is just a response for a SYNACK, don't keep*/ + fire_and_forget (message, ch, GNUNET_YES); + return; + } + /* fall-trough */ + case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK: + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE: + chq = GNUNET_new (struct CadetChannelQueue); + chq->type = type; + chq->rel = fwd ? ch->root_rel : ch->dest_rel; + if (NULL != chq->rel->uniq) + { + if (NULL != chq->rel->uniq->tq) + { + GMT_cancel (chq->rel->uniq->tq); + /* ch_message_sent is called, freeing and NULLing uniq */ + } + else + { + GNUNET_break (0); + GNUNET_free (chq->rel->uniq); + } + } + chq->tq = GMT_send_prebuilt_message (message, ch->t, NULL, GNUNET_YES, + &ch_message_sent, chq); + if (NULL == chq->tq) + { + GNUNET_break (0); + GNUNET_free (chq); + chq = NULL; + return; + } + chq->rel->uniq = chq; + break; + + + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK: + fire_and_forget (message, ch, GNUNET_YES); + break; + + + default: + GNUNET_break (0); + LOG (GNUNET_ERROR_TYPE_DEBUG, "type %s unknown!\n", GM_m2s (type)); + fire_and_forget (message, ch, GNUNET_YES); + } +} + + +/** + * Get the static string for identification of the channel. + * + * @param ch Channel. + * + * @return Static string with the channel IDs. + */ +const char * +GMCH_2s (const struct CadetChannel *ch) +{ + static char buf[64]; + + if (NULL == ch) + return "(NULL Channel)"; + + sprintf (buf, "%s:%u gid:%X (%X / %X)", + GMT_2s (ch->t), ch->port, ch->gid, ch->lid_root, ch->lid_dest); + + return buf; +} diff --git a/src/cadet/gnunet-service-cadet_channel.h b/src/cadet/gnunet-service-cadet_channel.h new file mode 100644 index 000000000..f5a89a423 --- /dev/null +++ b/src/cadet/gnunet-service-cadet_channel.h @@ -0,0 +1,349 @@ +/* + This file is part of GNUnet. + (C) 2013 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 cadet/gnunet-service-cadet_channel.h + * @brief cadet service; dealing with end-to-end channels + * @author Bartlomiej Polot + * + * All functions in this file should use the prefix GMCH (Gnunet Cadet CHannel) + */ + +#ifndef GNUNET_SERVICE_CADET_CHANNEL_H +#define GNUNET_SERVICE_CADET_CHANNEL_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "platform.h" +#include "gnunet_util_lib.h" + +#include "cadet_protocol.h" +#include "cadet.h" + +/** + * Struct containing all information regarding a channel to a remote client. + */ +struct CadetChannel; + + +#include "gnunet-service-cadet_tunnel.h" +#include "gnunet-service-cadet_local.h" + + +/** + * Destroy a channel and free all resources. + * + * @param ch Channel to destroy. + */ +void +GMCH_destroy (struct CadetChannel *ch); + + +/** + * Get the channel's public ID. + * + * @param ch Channel. + * + * @return ID used to identify the channel with the remote peer. + */ +CADET_ChannelNumber +GMCH_get_id (const struct CadetChannel *ch); + +/** + * Get the channel tunnel. + * + * @param ch Channel to get the tunnel from. + * + * @return tunnel of the channel. + */ +struct CadetTunnel3 * +GMCH_get_tunnel (const struct CadetChannel *ch); + +/** + * Get free buffer space towards the client on a specific channel. + * + * @param ch Channel. + * @param fwd Is query about FWD traffic? + * + * @return Free buffer space [0 - 64] + */ +unsigned int +GMCH_get_buffer (struct CadetChannel *ch, int fwd); + + +/** + * Get flow control status of end point: is client allow to send? + * + * @param ch Channel. + * @param fwd Is query about FWD traffic? (Request root status). + * + * @return #GNUNET_YES if client is allowed to send us data. + */ +int +GMCH_get_allowed (struct CadetChannel *ch, int fwd); + + +/** + * Is the root client for this channel on this peer? + * + * @param ch Channel. + * @param fwd Is this for fwd traffic? + * + * @return #GNUNET_YES in case it is. + */ +int +GMCH_is_origin (struct CadetChannel *ch, int fwd); + +/** + * Is the destination client for this channel on this peer? + * + * @param ch Channel. + * @param fwd Is this for fwd traffic? + * + * @return #GNUNET_YES in case it is. + */ +int +GMCH_is_terminal (struct CadetChannel *ch, int fwd); + +/** + * Send an end-to-end ACK message for the most recent in-sequence payload. + * + * If channel is not reliable, do nothing. + * + * @param ch Channel this is about. + * @param fwd Is for FWD traffic? (ACK dest->owner) + */ +void +GMCH_send_data_ack (struct CadetChannel *ch, int fwd); + +/** + * Notify the destination client that a new incoming channel was created. + * + * @param ch Channel that was created. + */ +void +GMCH_send_create (struct CadetChannel *ch); + +/** + * Allow a client to send us more data, in case it was choked. + * + * @param ch Channel. + * @param fwd Is this about FWD traffic? (Root client). + */ +void +GMCH_allow_client (struct CadetChannel *ch, int fwd); + +/** + * Log channel info. + * + * @param ch Channel. + */ +void +GMCH_debug (struct CadetChannel *ch); + +/** + * Handle an ACK given by a client. + * + * Mark client as ready and send him any buffered data we could have for him. + * + * @param ch Channel. + * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by root and go BCK) + */ +void +GMCH_handle_local_ack (struct CadetChannel *ch, int fwd); + +/** + * Handle data given by a client. + * + * Check whether the client is allowed to send in this tunnel, save if channel + * is reliable and send an ACK to the client if there is still buffer space + * in the tunnel. + * + * @param ch Channel. + * @param c Client which sent the data. + * @param message Message. + * @param fwd Is this a FWD data? + * + * @return GNUNET_OK if everything goes well, GNUNET_SYSERR in case of en error. + */ +int +GMCH_handle_local_data (struct CadetChannel *ch, + struct CadetClient *c, + struct GNUNET_MessageHeader *message, + int fwd); + +/** + * Handle a channel destroy requested by a client. + * + * Destroy the channel and the tunnel in case this was the last channel. + * + * @param ch Channel. + * @param c Client that requested the destruction (to avoid notifying him). + * @param is_root Is the request coming from root? + */ +void +GMCH_handle_local_destroy (struct CadetChannel *ch, + struct CadetClient *c, + int is_root); + +/** + * Handle a channel create requested by a client. + * + * Create the channel and the tunnel in case this was the first0 channel. + * + * @param c Client that requested the creation (will be the root). + * @param msg Create Channel message. + * + * @return GNUNET_OK if everything went fine, GNUNET_SYSERR otherwise. + */ +int +GMCH_handle_local_create (struct CadetClient *c, + struct GNUNET_CADET_ChannelMessage *msg); + +/** + * Handler for cadet network payload traffic. + * + * @param ch Channel for the message. + * @param msg Unencryted data message. + * @param fwd Is this message fwd? This only is meaningful in loopback channels. + * #GNUNET_YES if message is FWD on the respective channel (loopback) + * #GNUNET_NO if message is BCK on the respective channel (loopback) + * #GNUNET_SYSERR if message on a one-ended channel (remote) + */ +void +GMCH_handle_data (struct CadetChannel *ch, + const struct GNUNET_CADET_Data *msg, + int fwd); + +/** + * Handler for cadet network traffic end-to-end ACKs. + * + * @param ch Channel on which we got this message. + * @param msg Data message. + * @param fwd Is this message fwd? This only is meaningful in loopback channels. + * #GNUNET_YES if message is FWD on the respective channel (loopback) + * #GNUNET_NO if message is BCK on the respective channel (loopback) + * #GNUNET_SYSERR if message on a one-ended channel (remote) + */ +void +GMCH_handle_data_ack (struct CadetChannel *ch, + const struct GNUNET_CADET_DataACK *msg, + int fwd); + +/** + * Handler for channel create messages. + * + * Does not have fwd parameter because it's always 'FWD': channel is incoming. + * + * @param t Tunnel this channel will be in. + * @param msg Channel crate message. + */ +struct CadetChannel * +GMCH_handle_create (struct CadetTunnel3 *t, + const struct GNUNET_CADET_ChannelCreate *msg); + +/** + * Handler for channel NACK messages. + * + * NACK messages always go dest -> root, no need for 'fwd' or 'msg' parameter. + * + * @param ch Channel. + */ +void +GMCH_handle_nack (struct CadetChannel *ch); + +/** + * Handler for channel ack messages. + * + * @param ch Channel this channel is to be created in. + * @param msg Message. + * @param fwd Is this message fwd? This only is meaningful in loopback channels. + * #GNUNET_YES if message is FWD on the respective channel (loopback) + * #GNUNET_NO if message is BCK on the respective channel (loopback) + * #GNUNET_SYSERR if message on a one-ended channel (remote) + */ +void +GMCH_handle_ack (struct CadetChannel *ch, + const struct GNUNET_CADET_ChannelManage *msg, + int fwd); + +/** + * Handler for channel destroy messages. + * + * @param ch Channel this channel is to be destroyed of. + * @param msg Message. + * @param fwd Is this message fwd? This only is meaningful in loopback channels. + * #GNUNET_YES if message is FWD on the respective channel (loopback) + * #GNUNET_NO if message is BCK on the respective channel (loopback) + * #GNUNET_SYSERR if message on a one-ended channel (remote) + */ +void +GMCH_handle_destroy (struct CadetChannel *ch, + const struct GNUNET_CADET_ChannelManage *msg, + int fwd); + +/** + * Sends an already built message on a channel. + * + * If the channel is on a loopback tunnel, notifies the appropriate destination + * client locally. + * + * On a normal channel passes the message to the tunnel for encryption and + * sending on a connection. + * + * This function DOES NOT save the message for retransmission. + * + * @param message Message to send. Function makes a copy of it. + * @param ch Channel on which this message is transmitted. + * @param fwd Is this a fwd message? + * @param existing_copy This is a retransmission, don't save a copy. + */ +void +GMCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message, + struct CadetChannel *ch, int fwd, + void *existing_copy); + +/** + * Get the static string for identification of the channel. + * + * @param ch Channel.i + * + * @return Static string with the channel IDs. + */ +const char * +GMCH_2s (const struct CadetChannel *ch); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_SERVICE_CADET_CHANNEL_H */ +#endif +/* end of gnunet-service-cadet_channel.h */ diff --git a/src/cadet/gnunet-service-cadet_connection.c b/src/cadet/gnunet-service-cadet_connection.c new file mode 100644 index 000000000..9c07e006b --- /dev/null +++ b/src/cadet/gnunet-service-cadet_connection.c @@ -0,0 +1,3176 @@ +/* + This file is part of GNUnet. + (C) 2001-2013 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 cadet/gnunet-service-cadet_connection.c + * @brief GNUnet CADET service connection handling + * @author Bartlomiej Polot + */ + +#include "platform.h" +#include "gnunet_util_lib.h" + +#include "gnunet_statistics_service.h" + +#include "cadet_path.h" +#include "cadet_protocol.h" +#include "cadet.h" +#include "gnunet-service-cadet_connection.h" +#include "gnunet-service-cadet_peer.h" +#include "gnunet-service-cadet_tunnel.h" + + +#define LOG(level, ...) GNUNET_log_from (level,"cadet-con",__VA_ARGS__) + +#define CADET_MAX_POLL_TIME GNUNET_TIME_relative_multiply (\ + GNUNET_TIME_UNIT_MINUTES,\ + 10) +#define AVG_MSGS 32 + + +/******************************************************************************/ +/******************************** STRUCTS **********************************/ +/******************************************************************************/ + +/** + * Struct to encapsulate all the Flow Control information to a peer to which + * we are directly connected (on a core level). + */ +struct CadetFlowControl +{ + /** + * Connection this controls. + */ + struct CadetConnection *c; + + /** + * How many messages are in the queue on this connection. + */ + unsigned int queue_n; + + /** + * How many messages do we accept in the queue. + */ + unsigned int queue_max; + + /** + * ID of the last packet sent towards the peer. + */ + uint32_t last_pid_sent; + + /** + * ID of the last packet received from the peer. + */ + uint32_t last_pid_recv; + + /** + * Last ACK sent to the peer (peer can't send more than this PID). + */ + uint32_t last_ack_sent; + + /** + * Last ACK sent towards the origin (for traffic towards leaf node). + */ + uint32_t last_ack_recv; + + /** + * Task to poll the peer in case of a lost ACK causes stall. + */ + GNUNET_SCHEDULER_TaskIdentifier poll_task; + + /** + * How frequently to poll for ACKs. + */ + struct GNUNET_TIME_Relative poll_time; + + /** + * Queued poll message, to cancel if not necessary anymore (got ACK). + */ + struct CadetConnectionQueue *poll_msg; + + /** + * Queued poll message, to cancel if not necessary anymore (got ACK). + */ + struct CadetConnectionQueue *ack_msg; +}; + +/** + * Keep a record of the last messages sent on this connection. + */ +struct CadetConnectionPerformance +{ + /** + * Circular buffer for storing measurements. + */ + double usecsperbyte[AVG_MSGS]; + + /** + * Running average of @c usecsperbyte. + */ + double avg; + + /** + * How many values of @c usecsperbyte are valid. + */ + uint16_t size; + + /** + * Index of the next "free" position in @c usecsperbyte. + */ + uint16_t idx; +}; + + +/** + * Struct containing all information regarding a connection to a peer. + */ +struct CadetConnection +{ + /** + * Tunnel this connection is part of. + */ + struct CadetTunnel3 *t; + + /** + * Flow control information for traffic fwd. + */ + struct CadetFlowControl fwd_fc; + + /** + * Flow control information for traffic bck. + */ + struct CadetFlowControl bck_fc; + + /** + * Measure connection performance on the endpoint. + */ + struct CadetConnectionPerformance *perf; + + /** + * ID of the connection. + */ + struct GNUNET_CADET_Hash id; + + /** + * State of the connection. + */ + enum CadetConnectionState state; + + /** + * Path being used for the tunnel. At the origin of the connection + * it's a pointer to the destination's path pool, otherwise just a copy. + */ + struct CadetPeerPath *path; + + /** + * Position of the local peer in the path. + */ + unsigned int own_pos; + + /** + * Task to keep the used paths alive at the owner, + * time tunnel out on all the other peers. + */ + GNUNET_SCHEDULER_TaskIdentifier fwd_maintenance_task; + + /** + * Task to keep the used paths alive at the destination, + * time tunnel out on all the other peers. + */ + GNUNET_SCHEDULER_TaskIdentifier bck_maintenance_task; + + /** + * Queue handle for maintainance traffic. One handle for FWD and BCK since + * one peer never needs to maintain both directions (no loopback connections). + */ + struct CadetPeerQueue *maintenance_q; + + /** + * Counter to do exponential backoff when creating a connection (max 64). + */ + unsigned short create_retry; + + /** + * Pending message count. + */ + int pending_messages; + + /** + * Destroy flag: if true, destroy on last message. + */ + int destroy; +}; + +/** + * Handle for messages queued but not yet sent. + */ +struct CadetConnectionQueue +{ + /** + * Peer queue handle, to cancel if necessary. + */ + struct CadetPeerQueue *q; + + /** + * Was this a forced message? (Do not account for it) + */ + int forced; + + /** + * Continuation to call once sent. + */ + GMC_sent cont; + + /** + * Closure for @c cont. + */ + void *cont_cls; +}; + +/******************************************************************************/ +/******************************* GLOBALS ***********************************/ +/******************************************************************************/ + +/** + * Global handle to the statistics service. + */ +extern struct GNUNET_STATISTICS_Handle *stats; + +/** + * Local peer own ID (memory efficient handle). + */ +extern GNUNET_PEER_Id myid; + +/** + * Local peer own ID (full value). + */ +extern struct GNUNET_PeerIdentity my_full_id; + +/** + * Connections known, indexed by cid (CadetConnection). + */ +static struct GNUNET_CONTAINER_MultiHashMap *connections; + +/** + * How many connections are we willing to maintain. + * Local connections are always allowed, even if there are more connections than max. + */ +static unsigned long long max_connections; + +/** + * How many messages *in total* are we willing to queue, divide by number of + * connections to get connection queue size. + */ +static unsigned long long max_msgs_queue; + +/** + * How often to send path keepalives. Paths timeout after 4 missed. + */ +static struct GNUNET_TIME_Relative refresh_connection_time; + +/** + * How often to send path create / ACKs. + */ +static struct GNUNET_TIME_Relative create_connection_time; + + +/******************************************************************************/ +/******************************** STATIC ***********************************/ +/******************************************************************************/ + +#if 0 // avoid compiler warning for unused static function +static void +fc_debug (struct CadetFlowControl *fc) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, " IN: %u/%u\n", + fc->last_pid_recv, fc->last_ack_sent); + LOG (GNUNET_ERROR_TYPE_DEBUG, " OUT: %u/%u\n", + fc->last_pid_sent, fc->last_ack_recv); + LOG (GNUNET_ERROR_TYPE_DEBUG, " QUEUE: %u/%u\n", + fc->queue_n, fc->queue_max); +} + +static void +connection_debug (struct CadetConnection *c) +{ + if (NULL == c) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "*** DEBUG NULL CONNECTION ***\n"); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s:%X\n", + peer2s (c->t->peer), GMC_2s (c)); + LOG (GNUNET_ERROR_TYPE_DEBUG, " state: %u, pending msgs: %u\n", + c->state, c->pending_messages); + LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD FC\n"); + fc_debug (&c->fwd_fc); + LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK FC\n"); + fc_debug (&c->bck_fc); +} +#endif + + +/** + * Schedule next keepalive task, taking in consideration + * the connection state and number of retries. + * + * @param c Connection for which to schedule the next keepalive. + * @param fwd Direction for the next keepalive. + */ +static void +schedule_next_keepalive (struct CadetConnection *c, int fwd); + + +/** + * Resets the connection timeout task, some other message has done the + * task's job. + * - For the first peer on the direction this means to send + * a keepalive or a path confirmation message (either create or ACK). + * - For all other peers, this means to destroy the connection, + * due to lack of activity. + * Starts the timeout if no timeout was running (connection just created). + * + * @param c Connection whose timeout to reset. + * @param fwd Is this forward? + */ +static void +connection_reset_timeout (struct CadetConnection *c, int fwd); + + +/** + * Get string description for tunnel state. Reentrant. + * + * @param s Tunnel state. + * + * @return String representation. + */ +static const char * +GMC_state2s (enum CadetConnectionState s) +{ + switch (s) + { + case CADET_CONNECTION_NEW: + return "CADET_CONNECTION_NEW"; + case CADET_CONNECTION_SENT: + return "CADET_CONNECTION_SENT"; + case CADET_CONNECTION_ACK: + return "CADET_CONNECTION_ACK"; + case CADET_CONNECTION_READY: + return "CADET_CONNECTION_READY"; + case CADET_CONNECTION_DESTROYED: + return "CADET_CONNECTION_DESTROYED"; + default: + return "CADET_CONNECTION_STATE_ERROR"; + } +} + + +/** + * Initialize a Flow Control structure to the initial state. + * + * @param fc Flow Control structure to initialize. + */ +static void +fc_init (struct CadetFlowControl *fc) +{ + fc->last_pid_sent = (uint32_t) -1; /* Next (expected) = 0 */ + fc->last_pid_recv = (uint32_t) -1; + fc->last_ack_sent = (uint32_t) 0; + fc->last_ack_recv = (uint32_t) 0; + fc->poll_task = GNUNET_SCHEDULER_NO_TASK; + fc->poll_time = GNUNET_TIME_UNIT_SECONDS; + fc->queue_n = 0; + fc->queue_max = (max_msgs_queue / max_connections) + 1; +} + + +/** + * Find a connection. + * + * @param cid Connection ID. + */ +static struct CadetConnection * +connection_get (const struct GNUNET_CADET_Hash *cid) +{ + return GNUNET_CONTAINER_multihashmap_get (connections, GM_h2hc (cid)); +} + + +static void +connection_change_state (struct CadetConnection* c, + enum CadetConnectionState state) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Connection %s state %s -> %s\n", + GMC_2s (c), GMC_state2s (c->state), GMC_state2s (state)); + if (CADET_CONNECTION_DESTROYED == c->state) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "state not changing anymore\n"); + return; + } + c->state = state; + if (CADET_CONNECTION_READY == state) + c->create_retry = 1; +} + + +/** + * Callback called when a queued ACK message is sent. + * + * @param cls Closure (FC). + * @param c Connection this message was on. + * @param q Queue handler this call invalidates. + * @param type Type of message sent. + * @param fwd Was this a FWD going message? + * @param size Size of the message. + */ +static void +ack_sent (void *cls, + struct CadetConnection *c, + struct CadetConnectionQueue *q, + uint16_t type, int fwd, size_t size) +{ + struct CadetFlowControl *fc = cls; + + fc->ack_msg = NULL; +} + + +/** + * Send an ACK on the connection, informing the predecessor about + * the available buffer space. Should not be called in case the peer + * is origin (no predecessor) in the @c fwd direction. + * + * Note that for fwd ack, the FWD mean forward *traffic* (root->dest), + * the ACK itself goes "back" (dest->root). + * + * @param c Connection on which to send the ACK. + * @param buffer How much space free to advertise? + * @param fwd Is this FWD ACK? (Going dest -> root) + * @param force Don't optimize out. + */ +static void +send_ack (struct CadetConnection *c, unsigned int buffer, int fwd, int force) +{ + struct CadetFlowControl *next_fc; + struct CadetFlowControl *prev_fc; + struct GNUNET_CADET_ACK msg; + uint32_t ack; + int delta; + + /* If origin, there is no connection to send ACKs. Wrong function! */ + if (GMC_is_origin (c, fwd)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "connection %s is origin in %s\n", + GMC_2s (c), GM_f2s (fwd)); + GNUNET_break (0); + return; + } + + next_fc = fwd ? &c->fwd_fc : &c->bck_fc; + prev_fc = fwd ? &c->bck_fc : &c->fwd_fc; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "connection send %s ack on %s\n", + GM_f2s (fwd), GMC_2s (c)); + + /* Check if we need to transmit the ACK. */ + delta = prev_fc->last_ack_sent - prev_fc->last_pid_recv; + if (3 < delta && buffer < delta && GNUNET_NO == force) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending ACK, buffer > 3\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, + " last pid recv: %u, last ack sent: %u\n", + prev_fc->last_pid_recv, prev_fc->last_ack_sent); + return; + } + + /* Ok, ACK might be necessary, what PID to ACK? */ + ack = prev_fc->last_pid_recv + buffer; + LOG (GNUNET_ERROR_TYPE_DEBUG, " ACK %u\n", ack); + LOG (GNUNET_ERROR_TYPE_DEBUG, + " last pid %u, last ack %u, qmax %u, q %u\n", + prev_fc->last_pid_recv, prev_fc->last_ack_sent, + next_fc->queue_max, next_fc->queue_n); + if (ack == prev_fc->last_ack_sent && GNUNET_NO == force) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending FWD ACK, not needed\n"); + return; + } + + /* Check if message is already in queue */ + if (NULL != prev_fc->ack_msg) + { + if (GM_is_pid_bigger (ack, prev_fc->last_ack_sent)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " canceling old ACK\n"); + GMC_cancel (prev_fc->ack_msg); + /* GMC_cancel triggers ack_sent(), which clears fc->ack_msg */ + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " same ACK already in queue\n"); + return; + } + } + + prev_fc->last_ack_sent = ack; + + /* Build ACK message and send on connection */ + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_ACK); + msg.ack = htonl (ack); + msg.cid = c->id; + + prev_fc->ack_msg = GMC_send_prebuilt_message (&msg.header, + GNUNET_MESSAGE_TYPE_CADET_ACK, + ack, c, !fwd, GNUNET_YES, + &ack_sent, prev_fc); +} + + +/** + * Callback called when a connection queued message is sent. + * + * Calculates the average time and connection packet tracking. + * + * @param cls Closure (ConnectionQueue Handle). + * @param c Connection this message was on. + * @param sent Was it really sent? (Could have been canceled) + * @param type Type of message sent. + * @param pid Packet ID, or 0 if not applicable (create, destroy, etc). + * @param fwd Was this a FWD going message? + * @param size Size of the message. + * @param wait Time spent waiting for core (only the time for THIS message) + */ +static void +conn_message_sent (void *cls, + struct CadetConnection *c, int sent, + uint16_t type, uint32_t pid, int fwd, size_t size, + struct GNUNET_TIME_Relative wait) +{ + struct CadetConnectionPerformance *p; + struct CadetFlowControl *fc; + struct CadetConnectionQueue *q = cls; + double usecsperbyte; + int forced; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "connection message_sent\n"); + + fc = fwd ? &c->fwd_fc : &c->bck_fc; + LOG (GNUNET_ERROR_TYPE_DEBUG, " %ssent %s %s\n", + sent ? "" : "not ", GM_f2s (fwd), GM_m2s (type)); + if (NULL != q) + { + forced = q->forced; + if (NULL != q->cont) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " calling cont\n"); + q->cont (q->cont_cls, c, q, type, fwd, size); + } + GNUNET_free (q); + } + else if (type == GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED) + { + /* If NULL == q and ENCRYPTED == type, message must have been ch_mngmnt */ + forced = GNUNET_YES; + } + else + { + forced = GNUNET_NO; + } + if (NULL == c) + { + GNUNET_break (type == GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN || + type == GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY); + LOG (GNUNET_ERROR_TYPE_ERROR, "Message %s sent on NULL connection!\n", + GM_m2s (type)); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P- %p %u\n", c, c->pending_messages); + c->pending_messages--; + if (GNUNET_YES == c->destroy && 0 == c->pending_messages) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "! destroying connection!\n"); + GMC_destroy (c); + return; + } + /* Send ACK if needed, after accounting for sent ID in fc->queue_n */ + switch (type) + { + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE: + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK: + c->maintenance_q = NULL; + /* Don't trigger a keepalive for sent ACKs, only SYN and SYNACKs */ + if (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE == type || !fwd) + schedule_next_keepalive (c, fwd); + break; + + case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED: + if (GNUNET_YES == sent) + { + GNUNET_assert (NULL != q); + fc->last_pid_sent = pid; // FIXME + GMC_send_ack (c, fwd, GNUNET_NO); + connection_reset_timeout (c, fwd); + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, "! Q_N- %p %u\n", fc, fc->queue_n); + if (GNUNET_NO == forced) + { + fc->queue_n--; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "! accounting pid %u\n", + fc->last_pid_sent); + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "! forced, Q_N not accounting pid %u\n", + fc->last_pid_sent); + } + break; + + case GNUNET_MESSAGE_TYPE_CADET_KX: + if (GNUNET_YES == sent) + connection_reset_timeout (c, fwd); + break; + + case GNUNET_MESSAGE_TYPE_CADET_POLL: + fc->poll_msg = NULL; + break; + + case GNUNET_MESSAGE_TYPE_CADET_ACK: + fc->ack_msg = NULL; + break; + + default: + break; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "! message sent!\n"); + + if (NULL == c->perf) + return; /* Only endpoints are interested in timing. */ + + p = c->perf; + usecsperbyte = ((double) wait.rel_value_us) / size; + if (p->size == AVG_MSGS) + { + /* Array is full. Substract oldest value, add new one and store. */ + p->avg -= (p->usecsperbyte[p->idx] / AVG_MSGS); + p->usecsperbyte[p->idx] = usecsperbyte; + p->avg += (p->usecsperbyte[p->idx] / AVG_MSGS); + } + else + { + /* Array not yet full. Add current value to avg and store. */ + p->usecsperbyte[p->idx] = usecsperbyte; + p->avg *= p->size; + p->avg += p->usecsperbyte[p->idx]; + p->size++; + p->avg /= p->size; + } + p->idx = (p->idx + 1) % AVG_MSGS; +} + + +/** + * Get the previous hop in a connection + * + * @param c Connection. + * + * @return Previous peer in the connection. + */ +static struct CadetPeer * +get_prev_hop (const struct CadetConnection *c) +{ + GNUNET_PEER_Id id; + + LOG (GNUNET_ERROR_TYPE_DEBUG, " get prev hop %s [%u/%u]\n", + GMC_2s (c), c->own_pos, c->path->length); + if (0 == c->own_pos || c->path->length < 2) + id = c->path->peers[0]; + else + id = c->path->peers[c->own_pos - 1]; + + LOG (GNUNET_ERROR_TYPE_DEBUG, " ID: %s (%u)\n", + GNUNET_i2s (GNUNET_PEER_resolve2 (id)), id); + + return GMP_get_short (id); +} + + +/** + * Get the next hop in a connection + * + * @param c Connection. + * + * @return Next peer in the connection. + */ +static struct CadetPeer * +get_next_hop (const struct CadetConnection *c) +{ + GNUNET_PEER_Id id; + + LOG (GNUNET_ERROR_TYPE_DEBUG, " get next hop %s [%u/%u]\n", + GMC_2s (c), c->own_pos, c->path->length); + if ((c->path->length - 1) == c->own_pos || c->path->length < 2) + id = c->path->peers[c->path->length - 1]; + else + id = c->path->peers[c->own_pos + 1]; + + LOG (GNUNET_ERROR_TYPE_DEBUG, " ID: %s (%u)\n", + GNUNET_i2s (GNUNET_PEER_resolve2 (id)), id); + + return GMP_get_short (id); +} + + +/** + * Get the hop in a connection. + * + * @param c Connection. + * @param fwd Next hop? + * + * @return Next peer in the connection. + */ +static struct CadetPeer * +get_hop (struct CadetConnection *c, int fwd) +{ + if (fwd) + return get_next_hop (c); + return get_prev_hop (c); +} + + +/** + * Is traffic coming from this sender 'FWD' traffic? + * + * @param c Connection to check. + * @param sender Peer identity of neighbor. + * + * @return #GNUNET_YES in case the sender is the 'prev' hop and therefore + * the traffic is 'FWD'. + * #GNUNET_NO for BCK. + * #GNUNET_SYSERR for errors. + */ +static int +is_fwd (const struct CadetConnection *c, + const struct GNUNET_PeerIdentity *sender) +{ + GNUNET_PEER_Id id; + + id = GNUNET_PEER_search (sender); + if (GMP_get_short_id (get_prev_hop (c)) == id) + return GNUNET_YES; + + if (GMP_get_short_id (get_next_hop (c)) == id) + return GNUNET_NO; + + GNUNET_break (0); + return GNUNET_SYSERR; +} + + +/** + * Sends a CONNECTION ACK message in reponse to a received CONNECTION_CREATE + * or a first CONNECTION_ACK directed to us. + * + * @param connection Connection to confirm. + * @param fwd Should we send it FWD? (root->dest) + * (First (~SYNACK) goes BCK, second (~ACK) goes FWD) + */ +static void +send_connection_ack (struct CadetConnection *connection, int fwd) +{ + struct CadetTunnel3 *t; + + t = connection->t; + LOG (GNUNET_ERROR_TYPE_INFO, "===> {%14s ACK} on connection %s\n", + GM_f2s (!fwd), GMC_2s (connection)); + GMP_queue_add (get_hop (connection, fwd), NULL, + GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK, + GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK, 0, + sizeof (struct GNUNET_CADET_ConnectionACK), + connection, fwd, &conn_message_sent, NULL); + connection->pending_messages++; + if (CADET_TUNNEL3_NEW == GMT_get_cstate (t)) + GMT_change_cstate (t, CADET_TUNNEL3_WAITING); + if (CADET_CONNECTION_READY != connection->state) + connection_change_state (connection, CADET_CONNECTION_SENT); +} + + +/** + * Send a notification that a connection is broken. + * + * @param c Connection that is broken. + * @param id1 Peer that has disconnected. + * @param id2 Peer that has disconnected. + * @param fwd Direction towards which to send it. + */ +static void +send_broken (struct CadetConnection *c, + const struct GNUNET_PeerIdentity *id1, + const struct GNUNET_PeerIdentity *id2, + int fwd) +{ + struct GNUNET_CADET_ConnectionBroken msg; + + msg.header.size = htons (sizeof (struct GNUNET_CADET_ConnectionBroken)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN); + msg.cid = c->id; + msg.peer1 = *id1; + msg.peer2 = *id2; + GMC_send_prebuilt_message (&msg.header, + GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN, 0, + c, fwd, GNUNET_YES, NULL, NULL); +} + + +/** + * Send a notification that a connection is broken, when a connection + * isn't even known to the local peer. + * + * @param connection_id Connection ID. + * @param id1 Peer that has disconnected, probably local peer. + * @param id2 Peer that has disconnected can be NULL if unknown. + * @param peer Peer to notify (neighbor who sent the connection). + */ +static void +send_broken_unknown (const struct GNUNET_CADET_Hash *connection_id, + const struct GNUNET_PeerIdentity *id1, + const struct GNUNET_PeerIdentity *id2, + const struct GNUNET_PeerIdentity *peer_id) +{ + struct GNUNET_CADET_ConnectionBroken *msg; + struct CadetPeer *neighbor; + + LOG (GNUNET_ERROR_TYPE_INFO, "===> BROKEN on unknown connection %s\n", + GNUNET_h2s (GM_h2hc (connection_id))); + + msg = GNUNET_new (struct GNUNET_CADET_ConnectionBroken); + msg->header.size = htons (sizeof (struct GNUNET_CADET_ConnectionBroken)); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN); + msg->cid = *connection_id; + msg->peer1 = *id1; + if (NULL != id2) + msg->peer2 = *id2; + else + memset (&msg->peer2, 0, sizeof (msg->peer2)); + neighbor = GMP_get (peer_id); + GMP_queue_add (neighbor, msg, + GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN, + GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN, 2, + sizeof (struct GNUNET_CADET_ConnectionBroken), + NULL, GNUNET_SYSERR, /* connection, fwd */ + NULL, NULL); /* continuation */ +} + + +/** + * Send keepalive packets for a connection. + * + * @param c Connection to keep alive.. + * @param fwd Is this a FWD keepalive? (owner -> dest). + */ +static void +send_connection_keepalive (struct CadetConnection *c, int fwd) +{ + struct GNUNET_MessageHeader msg; + struct CadetFlowControl *fc; + + LOG (GNUNET_ERROR_TYPE_INFO, + "keepalive %s for connection %s\n", + GM_f2s (fwd), GMC_2s (c)); + + fc = fwd ? &c->fwd_fc : &c->bck_fc; + if (0 < fc->queue_n) + { + LOG (GNUNET_ERROR_TYPE_INFO, "not sending keepalive, traffic in queue\n"); + } + + GNUNET_STATISTICS_update (stats, "# keepalives sent", 1, GNUNET_NO); + + GNUNET_assert (NULL != c->t); + msg.size = htons (sizeof (msg)); + msg.type = htons (GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE); + + GNUNET_assert (NULL == + GMT_send_prebuilt_message (&msg, c->t, c, + GNUNET_NO, NULL, NULL)); +} + + +/** + * Send CONNECTION_{CREATE/ACK} packets for a connection. + * + * @param c Connection for which to send the message. + * @param fwd If #GNUNET_YES, send CREATE, otherwise send ACK. + */ +static void +connection_recreate (struct CadetConnection *c, int fwd) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, "sending connection recreate\n"); + if (fwd) + GMC_send_create (c); + else + send_connection_ack (c, GNUNET_NO); +} + + +/** + * Generic connection timer management. + * Depending on the role of the peer in the connection will send the + * appropriate message (build or keepalive) + * + * @param c Conncetion to maintain. + * @param fwd Is FWD? + */ +static void +connection_maintain (struct CadetConnection *c, int fwd) +{ + if (GNUNET_NO != c->destroy) + return; + + if (CADET_TUNNEL3_SEARCHING == GMT_get_cstate (c->t)) + { + /* TODO DHT GET with RO_BART */ + return; + } + switch (c->state) + { + case CADET_CONNECTION_NEW: + GNUNET_break (0); + /* fall-through */ + case CADET_CONNECTION_SENT: + connection_recreate (c, fwd); + break; + case CADET_CONNECTION_READY: + send_connection_keepalive (c, fwd); + break; + default: + break; + } +} + + + +/** + * Keep the connection alive. + * + * @param c Connection to keep alive. + * @param fwd Direction. + * @param shutdown Are we shutting down? (Don't send traffic) + * Non-zero value for true, not necessarily GNUNET_YES. + */ +static void +connection_keepalive (struct CadetConnection *c, int fwd, int shutdown) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, "%s keepalive for %s\n", + GM_f2s (fwd), GMC_2s (c)); + + if (fwd) + c->fwd_maintenance_task = GNUNET_SCHEDULER_NO_TASK; + else + c->bck_maintenance_task = GNUNET_SCHEDULER_NO_TASK; + + if (GNUNET_NO != shutdown) + return; + + connection_maintain (c, fwd); + + /* Next execution will be scheduled by message_sent */ +} + + +/** + * Keep the connection alive in the FWD direction. + * + * @param cls Closure (connection to keepalive). + * @param tc TaskContext. + */ +static void +connection_fwd_keepalive (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + connection_keepalive ((struct CadetConnection *) cls, + GNUNET_YES, + tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN); +} + + +/** + * Keep the connection alive in the BCK direction. + * + * @param cls Closure (connection to keepalive). + * @param tc TaskContext. + */ +static void +connection_bck_keepalive (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + connection_keepalive ((struct CadetConnection *) cls, + GNUNET_NO, + tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN); +} + + +/** + * Schedule next keepalive task, taking in consideration + * the connection state and number of retries. + * + * If the peer is not the origin, do nothing. + * + * @param c Connection for which to schedule the next keepalive. + * @param fwd Direction for the next keepalive. + */ +static void +schedule_next_keepalive (struct CadetConnection *c, int fwd) +{ + struct GNUNET_TIME_Relative delay; + GNUNET_SCHEDULER_TaskIdentifier *task_id; + GNUNET_SCHEDULER_Task keepalive_task; + + if (GNUNET_NO == GMC_is_origin (c, fwd)) + return; + + /* Calculate delay to use, depending on the state of the connection */ + if (CADET_CONNECTION_READY == c->state) + { + delay = refresh_connection_time; + } + else + { + if (1 > c->create_retry) + c->create_retry = 1; + delay = GNUNET_TIME_relative_multiply (create_connection_time, + c->create_retry); + if (c->create_retry < 64) + c->create_retry *= 2; + } + + /* Select direction-dependent parameters */ + if (GNUNET_YES == fwd) + { + task_id = &c->fwd_maintenance_task; + keepalive_task = &connection_fwd_keepalive; + } + else + { + task_id = &c->bck_maintenance_task; + keepalive_task = &connection_bck_keepalive; + } + + /* Check that no one scheduled it before us */ + if (GNUNET_SCHEDULER_NO_TASK != *task_id) + { + /* No need for a _break. It can happen for instance when sending a SYNACK + * for a duplicate SYN: the first SYNACK scheduled the task. */ + GNUNET_SCHEDULER_cancel (*task_id); + } + + /* Schedule the task */ + *task_id = GNUNET_SCHEDULER_add_delayed (delay, keepalive_task, c); + LOG (GNUNET_ERROR_TYPE_DEBUG, "next keepalive in %s\n", + GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES)); +} + + +/** + * @brief Re-initiate traffic on this connection if necessary. + * + * Check if there is traffic queued towards this peer + * and the core transmit handle is NULL (traffic was stalled). + * If so, call core tmt rdy. + * + * @param c Connection on which initiate traffic. + * @param fwd Is this about fwd traffic? + */ +static void +connection_unlock_queue (struct CadetConnection *c, int fwd) +{ + struct CadetPeer *peer; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "connection_unlock_queue %s on %s\n", + GM_f2s (fwd), GMC_2s (c)); + + if (GMC_is_terminal (c, fwd)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " is terminal!\n"); + return; + } + + peer = get_hop (c, fwd); + GMP_queue_unlock (peer, c); +} + + +/** + * Cancel all transmissions that belong to a certain connection. + * + * If the connection is scheduled for destruction and no more messages are left, + * the connection will be destroyed by the continuation call. + * + * @param c Connection which to cancel. Might be destroyed during this call. + * @param fwd Cancel fwd traffic? + */ +static void +connection_cancel_queues (struct CadetConnection *c, int fwd) +{ + struct CadetFlowControl *fc; + struct CadetPeer *peer; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + " *** Cancel %s queues for connection %s\n", + GM_f2s (fwd), GMC_2s (c)); + if (NULL == c) + { + GNUNET_break (0); + return; + } + + fc = fwd ? &c->fwd_fc : &c->bck_fc; + if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task) + { + GNUNET_SCHEDULER_cancel (fc->poll_task); + fc->poll_task = GNUNET_SCHEDULER_NO_TASK; + LOG (GNUNET_ERROR_TYPE_DEBUG, " *** Cancel POLL in ccq for fc %p\n", fc); + } + peer = get_hop (c, fwd); + GMP_queue_cancel (peer, c); +} + + +/** + * Function called if a connection has been stalled for a while, + * possibly due to a missed ACK. Poll the neighbor about its ACK status. + * + * @param cls Closure (poll ctx). + * @param tc TaskContext. + */ +static void +connection_poll (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Callback called when a queued POLL message is sent. + * + * @param cls Closure (FC). + * @param c Connection this message was on. + * @param q Queue handler this call invalidates. + * @param type Type of message sent. + * @param fwd Was this a FWD going message? + * @param size Size of the message. + */ +static void +poll_sent (void *cls, + struct CadetConnection *c, + struct CadetConnectionQueue *q, + uint16_t type, int fwd, size_t size) +{ + struct CadetFlowControl *fc = cls; + + if (2 == c->destroy) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL canceled on shutdown\n"); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + " *** POLL sent for , scheduling new one!\n"); + fc->poll_msg = NULL; + fc->poll_time = GNUNET_TIME_STD_BACKOFF (fc->poll_time); + fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time, + &connection_poll, fc); + LOG (GNUNET_ERROR_TYPE_DEBUG, " task %u\n", fc->poll_task); + +} + +/** + * Function called if a connection has been stalled for a while, + * possibly due to a missed ACK. Poll the neighbor about its ACK status. + * + * @param cls Closure (poll ctx). + * @param tc TaskContext. + */ +static void +connection_poll (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CadetFlowControl *fc = cls; + struct GNUNET_CADET_Poll msg; + struct CadetConnection *c; + + fc->poll_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + { + return; + } + + c = fc->c; + LOG (GNUNET_ERROR_TYPE_DEBUG, " *** Polling connection %s %s\n", + GMC_2s (c), fc == &c->fwd_fc ? "FWD" : "BCK"); + + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_POLL); + msg.header.size = htons (sizeof (msg)); + msg.pid = htonl (fc->last_pid_sent); + LOG (GNUNET_ERROR_TYPE_DEBUG, " *** last pid sent: %u!\n", fc->last_pid_sent); + fc->poll_msg = + GMC_send_prebuilt_message (&msg.header, + GNUNET_MESSAGE_TYPE_CADET_POLL, + fc->last_pid_sent, + c, fc == &c->fwd_fc, GNUNET_YES, + &poll_sent, fc); +} + + +/** + * Timeout function due to lack of keepalive/traffic from the owner. + * Destroys connection if called. + * + * @param cls Closure (connection to destroy). + * @param tc TaskContext. + */ +static void +connection_fwd_timeout (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CadetConnection *c = cls; + + c->fwd_maintenance_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s FWD timed out. Destroying.\n", + GMC_2s (c)); + if (GMC_is_origin (c, GNUNET_YES)) /* If local, leave. */ + { + GNUNET_break (0); + return; + } + + GMC_destroy (c); +} + + +/** + * Timeout function due to lack of keepalive/traffic from the destination. + * Destroys connection if called. + * + * @param cls Closure (connection to destroy). + * @param tc TaskContext + */ +static void +connection_bck_timeout (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CadetConnection *c = cls; + + c->bck_maintenance_task = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s BCK timed out. Destroying.\n", + GMC_2s (c)); + + if (GMC_is_origin (c, GNUNET_NO)) /* If local, leave. */ + { + GNUNET_break (0); + return; + } + + GMC_destroy (c); +} + + +/** + * Resets the connection timeout task, some other message has done the + * task's job. + * - For the first peer on the direction this means to send + * a keepalive or a path confirmation message (either create or ACK). + * - For all other peers, this means to destroy the connection, + * due to lack of activity. + * Starts the timeout if no timeout was running (connection just created). + * + * @param c Connection whose timeout to reset. + * @param fwd Is this forward? + * + * TODO use heap to improve efficiency of scheduler. + */ +static void +connection_reset_timeout (struct CadetConnection *c, int fwd) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s reset timeout\n", GM_f2s (fwd)); + + if (GMC_is_origin (c, fwd)) /* Startpoint */ + { + schedule_next_keepalive (c, fwd); + } + else /* Relay, endpoint. */ + { + struct GNUNET_TIME_Relative delay; + GNUNET_SCHEDULER_TaskIdentifier *ti; + GNUNET_SCHEDULER_Task f; + + ti = fwd ? &c->fwd_maintenance_task : &c->bck_maintenance_task; + + if (GNUNET_SCHEDULER_NO_TASK != *ti) + GNUNET_SCHEDULER_cancel (*ti); + delay = GNUNET_TIME_relative_multiply (refresh_connection_time, 4); + f = fwd ? &connection_fwd_timeout : &connection_bck_timeout; + *ti = GNUNET_SCHEDULER_add_delayed (delay, f, c); + } +} + + +/** + * Add the connection to the list of both neighbors. + * + * @param c Connection. + * + * @return #GNUNET_OK if everything went fine + * #GNUNET_SYSERR if the was an error and @c c is malformed. + */ +static int +register_neighbors (struct CadetConnection *c) +{ + struct CadetPeer *next_peer; + struct CadetPeer *prev_peer; + + next_peer = get_next_hop (c); + prev_peer = get_prev_hop (c); + + LOG (GNUNET_ERROR_TYPE_DEBUG, "register neighbors for connection %s\n", + GMC_2s (c)); + path_debug (c->path); + LOG (GNUNET_ERROR_TYPE_DEBUG, "own pos %u\n", c->own_pos); + LOG (GNUNET_ERROR_TYPE_DEBUG, "putting connection %s to next peer %p\n", + GMC_2s (c), next_peer); + LOG (GNUNET_ERROR_TYPE_DEBUG, "next peer %p %s\n", next_peer, GMP_2s (next_peer)); + LOG (GNUNET_ERROR_TYPE_DEBUG, "putting connection %s to prev peer %p\n", + GMC_2s (c), prev_peer); + LOG (GNUNET_ERROR_TYPE_DEBUG, "prev peer %p %s\n", prev_peer, GMP_2s (prev_peer)); + + if (GNUNET_NO == GMP_is_neighbor (next_peer) + || GNUNET_NO == GMP_is_neighbor (prev_peer)) + { + if (GMC_is_origin (c, GNUNET_YES)) + GNUNET_STATISTICS_update (stats, "# local bad paths", 1, GNUNET_NO); + GNUNET_STATISTICS_update (stats, "# bad paths", 1, GNUNET_NO); + + LOG (GNUNET_ERROR_TYPE_DEBUG, " register neighbors failed\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, " prev: %s, neighbor?: %d\n", + GMP_2s (prev_peer), GMP_is_neighbor (prev_peer)); + LOG (GNUNET_ERROR_TYPE_DEBUG, " next: %s, neighbor?: %d\n", + GMP_2s (next_peer), GMP_is_neighbor (next_peer)); + return GNUNET_SYSERR; + } + + GMP_add_connection (next_peer, c); + GMP_add_connection (prev_peer, c); + + return GNUNET_OK; +} + + +/** + * Remove the connection from the list of both neighbors. + * + * @param c Connection. + */ +static void +unregister_neighbors (struct CadetConnection *c) +{ + struct CadetPeer *peer; + + peer = get_next_hop (c); + if (GNUNET_OK != GMP_remove_connection (peer, c)) + { + GNUNET_assert (CADET_CONNECTION_NEW == c->state + || CADET_CONNECTION_DESTROYED == c->state); + LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate: %u\n", c->state); + if (NULL != c->t) GMT_debug (c->t); + } + + peer = get_prev_hop (c); + if (GNUNET_OK != GMP_remove_connection (peer, c)) + { + GNUNET_assert (CADET_CONNECTION_NEW == c->state + || CADET_CONNECTION_DESTROYED == c->state); + LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate: %u\n", c->state); + if (NULL != c->t) GMT_debug (c->t); + } +} + + +/** + * Bind the connection to the peer and the tunnel to that peer. + * + * If the peer has no tunnel, create one. Update tunnel and connection + * data structres to reflect new status. + * + * @param c Connection. + * @param peer Peer. + */ +static void +add_to_peer (struct CadetConnection *c, struct CadetPeer *peer) +{ + GMP_add_tunnel (peer); + c->t = GMP_get_tunnel (peer); + GMT_add_connection (c->t, c); +} + + +/** + * Builds a path from a PeerIdentity array. + * + * @param peers PeerIdentity array. + * @param size Size of the @c peers array. + * @param own_pos Output parameter: own position in the path. + * + * @return Fixed and shortened path. + */ +static struct CadetPeerPath * +build_path_from_peer_ids (struct GNUNET_PeerIdentity *peers, + unsigned int size, + unsigned int *own_pos) +{ + struct CadetPeerPath *path; + GNUNET_PEER_Id shortid; + unsigned int i; + unsigned int j; + unsigned int offset; + + /* Create path */ + LOG (GNUNET_ERROR_TYPE_DEBUG, " Creating path...\n"); + path = path_new (size); + *own_pos = 0; + offset = 0; + for (i = 0; i < size; i++) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " - %u: taking %s\n", + i, GNUNET_i2s (&peers[i])); + shortid = GNUNET_PEER_intern (&peers[i]); + + /* Check for loops / duplicates */ + for (j = 0; j < i - offset; j++) + { + if (path->peers[j] == shortid) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " already exists at pos %u\n", j); + offset = i - j; + LOG (GNUNET_ERROR_TYPE_DEBUG, " offset now %u\n", offset); + GNUNET_PEER_change_rc (shortid, -1); + } + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " storing at %u\n", i - offset); + path->peers[i - offset] = shortid; + if (path->peers[i - offset] == myid) + *own_pos = i - offset; + } + path->length -= offset; + + if (path->peers[*own_pos] != myid) + { + /* create path: self not found in path through self */ + GNUNET_break_op (0); + path_destroy (path); + return NULL; + } + + return path; +} + + +/** + * Log receipt of message on stderr (INFO level). + * + * @param message Message received. + * @param peer Peer who sent the message. + * @param hash Connection ID. + */ +static void +log_message (const struct GNUNET_MessageHeader *message, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_CADET_Hash *hash) +{ + LOG (GNUNET_ERROR_TYPE_INFO, "<-- %s on connection %s from %s\n", + GM_m2s (ntohs (message->type)), GNUNET_h2s (GM_h2hc (hash)), + GNUNET_i2s (peer)); +} + +/******************************************************************************/ +/******************************** API ***********************************/ +/******************************************************************************/ + +/** + * Core handler for connection creation. + * + * @param cls Closure (unused). + * @param peer Sender (neighbor). + * @param message Message. + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +GMC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_CADET_ConnectionCreate *msg; + struct GNUNET_PeerIdentity *id; + struct GNUNET_CADET_Hash *cid; + struct CadetPeerPath *path; + struct CadetPeer *dest_peer; + struct CadetPeer *orig_peer; + struct CadetConnection *c; + unsigned int own_pos; + uint16_t size; + + /* Check size */ + size = ntohs (message->size); + if (size < sizeof (struct GNUNET_CADET_ConnectionCreate)) + { + GNUNET_break_op (0); + return GNUNET_OK; + } + + /* Calculate hops */ + size -= sizeof (struct GNUNET_CADET_ConnectionCreate); + if (size % sizeof (struct GNUNET_PeerIdentity)) + { + GNUNET_break_op (0); + return GNUNET_OK; + } + size /= sizeof (struct GNUNET_PeerIdentity); + if (1 > size) + { + GNUNET_break_op (0); + return GNUNET_OK; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " path has %u hops.\n", size); + + /* Get parameters */ + msg = (struct GNUNET_CADET_ConnectionCreate *) message; + cid = &msg->cid; + log_message (message, peer, cid); + id = (struct GNUNET_PeerIdentity *) &msg[1]; + LOG (GNUNET_ERROR_TYPE_DEBUG, " origin: %s\n", GNUNET_i2s (id)); + + /* Create connection */ + c = connection_get (cid); + if (NULL == c) + { + path = build_path_from_peer_ids ((struct GNUNET_PeerIdentity *) &msg[1], + size, &own_pos); + if (NULL == path) + return GNUNET_OK; + if (0 == own_pos) + { + GNUNET_break_op (0); + path_destroy (path); + return GNUNET_OK; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " Own position: %u\n", own_pos); + LOG (GNUNET_ERROR_TYPE_DEBUG, " Creating connection\n"); + c = GMC_new (cid, NULL, path_duplicate (path), own_pos); + if (NULL == c) + { + if (path->length - 1 == own_pos) + { + /* If we are destination, why did the creation fail? */ + GNUNET_break (0); + return GNUNET_OK; + } + send_broken_unknown (cid, &my_full_id, + GNUNET_PEER_resolve2 (path->peers[own_pos + 1]), + peer); + path_destroy (path); + return GNUNET_OK; + } + GMP_add_path_to_all (path, GNUNET_NO); + connection_reset_timeout (c, GNUNET_YES); + } + else + { + path = path_duplicate (c->path); + } + if (CADET_CONNECTION_NEW == c->state) + connection_change_state (c, CADET_CONNECTION_SENT); + + /* Remember peers */ + dest_peer = GMP_get (&id[size - 1]); + orig_peer = GMP_get (&id[0]); + + /* Is it a connection to us? */ + if (c->own_pos == path->length - 1) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " It's for us!\n"); + GMP_add_path_to_origin (orig_peer, path_duplicate (path), GNUNET_YES); + + add_to_peer (c, orig_peer); + if (CADET_TUNNEL3_NEW == GMT_get_cstate (c->t)) + GMT_change_cstate (c->t, CADET_TUNNEL3_WAITING); + + send_connection_ack (c, GNUNET_NO); + if (CADET_CONNECTION_SENT == c->state) + connection_change_state (c, CADET_CONNECTION_ACK); + } + else + { + /* It's for somebody else! Retransmit. */ + LOG (GNUNET_ERROR_TYPE_DEBUG, " Retransmitting.\n"); + GMP_add_path (dest_peer, path_duplicate (path), GNUNET_NO); + GMP_add_path_to_origin (orig_peer, path_duplicate (path), GNUNET_NO); + GMC_send_prebuilt_message (message, + GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, 0, + c, GNUNET_YES, GNUNET_YES, + NULL, NULL); + } + path_destroy (path); + return GNUNET_OK; +} + + +/** + * Core handler for path confirmations. + * + * @param cls closure + * @param message message + * @param peer peer identity this notification is about + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +GMC_handle_confirm (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_CADET_ConnectionACK *msg; + struct CadetConnection *c; + struct CadetPeerPath *p; + struct CadetPeer *pi; + enum CadetConnectionState oldstate; + int fwd; + + msg = (struct GNUNET_CADET_ConnectionACK *) message; + log_message (message, peer, &msg->cid); + c = connection_get (&msg->cid); + if (NULL == c) + { + GNUNET_STATISTICS_update (stats, "# control on unknown connection", + 1, GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_DEBUG, " don't know the connection!\n"); + send_broken_unknown (&msg->cid, &my_full_id, NULL, peer); + return GNUNET_OK; + } + + if (GNUNET_NO != c->destroy) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " connection being destroyed\n"); + return GNUNET_OK; + } + + oldstate = c->state; + LOG (GNUNET_ERROR_TYPE_DEBUG, " via peer %s\n", GNUNET_i2s (peer)); + pi = GMP_get (peer); + if (get_next_hop (c) == pi) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " SYNACK\n"); + fwd = GNUNET_NO; + if (CADET_CONNECTION_SENT == oldstate) + connection_change_state (c, CADET_CONNECTION_ACK); + } + else if (get_prev_hop (c) == pi) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " ACK\n"); + fwd = GNUNET_YES; + connection_change_state (c, CADET_CONNECTION_READY); + } + else + { + GNUNET_break_op (0); + return GNUNET_OK; + } + + connection_reset_timeout (c, fwd); + + /* Add path to peers? */ + p = c->path; + if (NULL != p) + { + GMP_add_path_to_all (p, GNUNET_YES); + } + else + { + GNUNET_break (0); + } + + /* Message for us as creator? */ + if (GMC_is_origin (c, GNUNET_YES)) + { + if (GNUNET_NO != fwd) + { + GNUNET_break_op (0); + return GNUNET_OK; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " Connection (SYN)ACK for us!\n"); + + /* If just created, cancel the short timeout and start a long one */ + if (CADET_CONNECTION_SENT == oldstate) + connection_reset_timeout (c, GNUNET_YES); + + /* Change connection state */ + connection_change_state (c, CADET_CONNECTION_READY); + send_connection_ack (c, GNUNET_YES); + + /* Change tunnel state, trigger KX */ + if (CADET_TUNNEL3_WAITING == GMT_get_cstate (c->t)) + GMT_change_cstate (c->t, CADET_TUNNEL3_READY); + + return GNUNET_OK; + } + + /* Message for us as destination? */ + if (GMC_is_terminal (c, GNUNET_YES)) + { + if (GNUNET_YES != fwd) + { + GNUNET_break_op (0); + return GNUNET_OK; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " Connection ACK for us!\n"); + + /* If just created, cancel the short timeout and start a long one */ + if (CADET_CONNECTION_ACK == oldstate) + connection_reset_timeout (c, GNUNET_NO); + + /* Change tunnel state */ + if (CADET_TUNNEL3_WAITING == GMT_get_cstate (c->t)) + GMT_change_cstate (c->t, CADET_TUNNEL3_READY); + + return GNUNET_OK; + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n"); + GMC_send_prebuilt_message (message, + GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK, 0, + c, fwd, GNUNET_YES, NULL, NULL); + return GNUNET_OK; +} + + +/** + * Core handler for notifications of broken connections. + * + * @param cls Closure (unused). + * @param id Peer identity of sending neighbor. + * @param message Message. + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +GMC_handle_broken (void* cls, + const struct GNUNET_PeerIdentity* id, + const struct GNUNET_MessageHeader* message) +{ + struct GNUNET_CADET_ConnectionBroken *msg; + struct CadetConnection *c; + int fwd; + + msg = (struct GNUNET_CADET_ConnectionBroken *) message; + log_message (message, id, &msg->cid); + LOG (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n", + GNUNET_i2s (&msg->peer1)); + LOG (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n", + GNUNET_i2s (&msg->peer2)); + c = connection_get (&msg->cid); + if (NULL == c) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate CONNECTION_BROKEN\n"); + return GNUNET_OK; + } + + fwd = is_fwd (c, id); + if (GMC_is_terminal (c, fwd)) + { + struct GNUNET_MessageHeader *out_msg; + struct CadetPeer *neighbor; + struct CadetPeer *endpoint; + + neighbor = get_hop (c, !fwd); + endpoint = GMP_get_short (c->path->peers[c->path->length - 1]); + path_invalidate (c->path); + GMP_notify_broken_link (endpoint, &msg->peer1, &msg->peer2); + c->state = CADET_CONNECTION_DESTROYED; + while (NULL != (out_msg = GMP_connection_pop (neighbor, c))) + { + GNUNET_assert (NULL == + GMT_send_prebuilt_message (out_msg, c->t, NULL, GNUNET_YES, + NULL, NULL)); + } + + GMC_destroy (c); + } + else + { + GMC_send_prebuilt_message (message, + GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN, 0, + c, fwd, GNUNET_YES, NULL, NULL); + c->destroy = GNUNET_YES; + connection_cancel_queues (c, !fwd); + } + + return GNUNET_OK; + +} + + +/** + * Core handler for tunnel destruction + * + * @param cls Closure (unused). + * @param peer Peer identity of sending neighbor. + * @param message Message. + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +GMC_handle_destroy (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_CADET_ConnectionDestroy *msg; + struct CadetConnection *c; + int fwd; + + msg = (struct GNUNET_CADET_ConnectionDestroy *) message; + log_message (message, peer, &msg->cid); + c = connection_get (&msg->cid); + if (NULL == c) + { + /* Probably already got the message from another path, + * destroyed the tunnel and retransmitted to children. + * Safe to ignore. + */ + GNUNET_STATISTICS_update (stats, "# control on unknown connection", + 1, GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_DEBUG, " connection unknown: already destroyed?\n"); + return GNUNET_OK; + } + fwd = is_fwd (c, peer); + if (GNUNET_SYSERR == fwd) + { + GNUNET_break_op (0); /* FIXME */ + return GNUNET_OK; + } + if (GNUNET_NO == GMC_is_terminal (c, fwd)) + GMC_send_prebuilt_message (message, + GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY, 0, + c, fwd, GNUNET_YES, NULL, NULL); + else if (0 == c->pending_messages) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " directly destroying connection!\n"); + GMC_destroy (c); + return GNUNET_OK; + } + c->destroy = GNUNET_YES; + c->state = CADET_CONNECTION_DESTROYED; + if (NULL != c->t) + { + GMT_remove_connection (c->t, c); + c->t = NULL; + } + + return GNUNET_OK; +} + +/** + * Generic handler for cadet network encrypted traffic. + * + * @param peer Peer identity this notification is about. + * @param msg Encrypted message. + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_cadet_encrypted (const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_CADET_Encrypted *msg) +{ + struct CadetConnection *c; + struct CadetPeer *neighbor; + struct CadetFlowControl *fc; + GNUNET_PEER_Id peer_id; + uint32_t pid; + uint32_t ttl; + size_t size; + int fwd; + + log_message (&msg->header, peer, &msg->cid); + + /* Check size */ + size = ntohs (msg->header.size); + if (size < + sizeof (struct GNUNET_CADET_Encrypted) + + sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break_op (0); + return GNUNET_OK; + } + + /* Check connection */ + c = connection_get (&msg->cid); + if (NULL == c) + { + GNUNET_STATISTICS_update (stats, "# unknown connection", 1, GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_DEBUG, "enc on unknown connection %s\n", + GNUNET_h2s (GM_h2hc (&msg->cid))); + send_broken_unknown (&msg->cid, &my_full_id, NULL, peer); + return GNUNET_OK; + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, " connection %s\n", GMC_2s (c)); + + /* Check if origin is as expected */ + neighbor = get_prev_hop (c); + peer_id = GNUNET_PEER_search (peer); + if (peer_id == GMP_get_short_id (neighbor)) + { + fwd = GNUNET_YES; + } + else + { + neighbor = get_next_hop (c); + if (peer_id == GMP_get_short_id (neighbor)) + { + fwd = GNUNET_NO; + } + else + { + /* Unexpected peer sending traffic on a connection. */ + GNUNET_break_op (0); + return GNUNET_OK; + } + } + + /* Check PID */ + fc = fwd ? &c->bck_fc : &c->fwd_fc; + pid = ntohl (msg->pid); + LOG (GNUNET_ERROR_TYPE_DEBUG, " PID %u (expected %u+)\n", + pid, fc->last_pid_recv + 1); + if (GM_is_pid_bigger (pid, fc->last_ack_sent)) + { + GNUNET_STATISTICS_update (stats, "# unsolicited message", 1, GNUNET_NO); + GNUNET_break_op (0); + LOG (GNUNET_ERROR_TYPE_WARNING, + "Received PID %u, (prev %u), ACK %u\n", + pid, fc->last_pid_recv, fc->last_ack_sent); + return GNUNET_OK; + } + if (GNUNET_NO == GM_is_pid_bigger (pid, fc->last_pid_recv)) + { + GNUNET_STATISTICS_update (stats, "# duplicate PID", 1, GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_DEBUG, + " PID %u not expected (%u+), dropping!\n", + pid, fc->last_pid_recv + 1); + return GNUNET_OK; + } + if (CADET_CONNECTION_SENT == c->state || CADET_CONNECTION_ACK == c->state) + connection_change_state (c, CADET_CONNECTION_READY); + connection_reset_timeout (c, fwd); + fc->last_pid_recv = pid; + + /* Is this message for us? */ + if (GMC_is_terminal (c, fwd)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " message for us!\n"); + GNUNET_STATISTICS_update (stats, "# messages received", 1, GNUNET_NO); + + if (NULL == c->t) + { + GNUNET_break (GNUNET_NO != c->destroy); + return GNUNET_OK; + } + fc->last_pid_recv = pid; + GMT_handle_encrypted (c->t, msg); + GMC_send_ack (c, fwd, GNUNET_NO); + return GNUNET_OK; + } + + /* Message not for us: forward to next hop */ + LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n"); + ttl = ntohl (msg->ttl); + LOG (GNUNET_ERROR_TYPE_DEBUG, " ttl: %u\n", ttl); + if (ttl == 0) + { + GNUNET_STATISTICS_update (stats, "# TTL drops", 1, GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_WARNING, " TTL is 0, DROPPING!\n"); + GMC_send_ack (c, fwd, GNUNET_NO); + return GNUNET_OK; + } + + GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO); + GMC_send_prebuilt_message (&msg->header, + GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED, 0, + c, fwd, GNUNET_NO, NULL, NULL); + + return GNUNET_OK; +} + +/** + * Generic handler for cadet network encrypted traffic. + * + * @param peer Peer identity this notification is about. + * @param msg Encrypted message. + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_cadet_kx (const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_CADET_KX *msg) +{ + struct CadetConnection *c; + struct CadetPeer *neighbor; + GNUNET_PEER_Id peer_id; + size_t size; + int fwd; + + log_message (&msg->header, peer, &msg->cid); + + /* Check size */ + size = ntohs (msg->header.size); + if (size < + sizeof (struct GNUNET_CADET_KX) + + sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break_op (0); + return GNUNET_OK; + } + + /* Check connection */ + c = connection_get (&msg->cid); + if (NULL == c) + { + GNUNET_STATISTICS_update (stats, "# unknown connection", 1, GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_DEBUG, "kx on unknown connection %s\n", + GNUNET_h2s (GM_h2hc (&msg->cid))); + send_broken_unknown (&msg->cid, &my_full_id, NULL, peer); + return GNUNET_OK; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " on connection %s\n", GMC_2s (c)); + + /* Check if origin is as expected */ + neighbor = get_prev_hop (c); + peer_id = GNUNET_PEER_search (peer); + if (peer_id == GMP_get_short_id (neighbor)) + { + fwd = GNUNET_YES; + } + else + { + neighbor = get_next_hop (c); + if (peer_id == GMP_get_short_id (neighbor)) + { + fwd = GNUNET_NO; + } + else + { + /* Unexpected peer sending traffic on a connection. */ + GNUNET_break_op (0); + return GNUNET_OK; + } + } + + /* Count as connection confirmation. */ + if (CADET_CONNECTION_SENT == c->state || CADET_CONNECTION_ACK == c->state) + { + connection_change_state (c, CADET_CONNECTION_READY); + if (NULL != c->t) + { + if (CADET_TUNNEL3_WAITING == GMT_get_cstate (c->t)) + GMT_change_cstate (c->t, CADET_TUNNEL3_READY); + } + } + connection_reset_timeout (c, fwd); + + /* Is this message for us? */ + if (GMC_is_terminal (c, fwd)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " message for us!\n"); + GNUNET_STATISTICS_update (stats, "# messages received", 1, GNUNET_NO); + if (NULL == c->t) + { + GNUNET_break (0); + return GNUNET_OK; + } + GMT_handle_kx (c->t, &msg[1].header); + return GNUNET_OK; + } + + /* Message not for us: forward to next hop */ + LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n"); + GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO); + GMC_send_prebuilt_message (&msg->header, GNUNET_MESSAGE_TYPE_CADET_KX, 0, + c, fwd, GNUNET_NO, NULL, NULL); + + return GNUNET_OK; +} + + +/** + * Core handler for encrypted cadet network traffic (channel mgmt, data). + * + * @param cls Closure (unused). + * @param message Message received. + * @param peer Peer who sent the message. + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +GMC_handle_encrypted (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message) +{ + return handle_cadet_encrypted (peer, + (struct GNUNET_CADET_Encrypted *)message); +} + + +/** + * Core handler for key exchange traffic (ephemeral key, ping, pong). + * + * @param cls Closure (unused). + * @param message Message received. + * @param peer Peer who sent the message. + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +GMC_handle_kx (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message) +{ + return handle_cadet_kx (peer, + (struct GNUNET_CADET_KX *) message); +} + + +/** + * Core handler for cadet network traffic point-to-point acks. + * + * @param cls closure + * @param message message + * @param peer peer identity this notification is about + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +GMC_handle_ack (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_CADET_ACK *msg; + struct CadetConnection *c; + struct CadetFlowControl *fc; + GNUNET_PEER_Id id; + uint32_t ack; + int fwd; + + msg = (struct GNUNET_CADET_ACK *) message; + log_message (message, peer, &msg->cid); + c = connection_get (&msg->cid); + if (NULL == c) + { + GNUNET_STATISTICS_update (stats, "# ack on unknown connection", 1, + GNUNET_NO); + send_broken_unknown (&msg->cid, &my_full_id, NULL, peer); + return GNUNET_OK; + } + + /* Is this a forward or backward ACK? */ + id = GNUNET_PEER_search (peer); + if (GMP_get_short_id (get_next_hop (c)) == id) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD ACK\n"); + fc = &c->fwd_fc; + fwd = GNUNET_YES; + } + else if (GMP_get_short_id (get_prev_hop (c)) == id) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK ACK\n"); + fc = &c->bck_fc; + fwd = GNUNET_NO; + } + else + { + GNUNET_break_op (0); + return GNUNET_OK; + } + + ack = ntohl (msg->ack); + LOG (GNUNET_ERROR_TYPE_DEBUG, " ACK %u (was %u)\n", + ack, fc->last_ack_recv); + if (GM_is_pid_bigger (ack, fc->last_ack_recv)) + fc->last_ack_recv = ack; + + /* Cancel polling if the ACK is big enough. */ + if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task && + GM_is_pid_bigger (fc->last_ack_recv, fc->last_pid_sent)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " Cancel poll\n"); + GNUNET_SCHEDULER_cancel (fc->poll_task); + fc->poll_task = GNUNET_SCHEDULER_NO_TASK; + fc->poll_time = GNUNET_TIME_UNIT_SECONDS; + } + + connection_unlock_queue (c, fwd); + + return GNUNET_OK; +} + + +/** + * Core handler for cadet network traffic point-to-point ack polls. + * + * @param cls closure + * @param message message + * @param peer peer identity this notification is about + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +GMC_handle_poll (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_CADET_Poll *msg; + struct CadetConnection *c; + struct CadetFlowControl *fc; + GNUNET_PEER_Id id; + uint32_t pid; + int fwd; + + msg = (struct GNUNET_CADET_Poll *) message; + log_message (message, peer, &msg->cid); + c = connection_get (&msg->cid); + if (NULL == c) + { + GNUNET_STATISTICS_update (stats, "# poll on unknown connection", 1, + GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL message on unknown connection %s!\n", + GNUNET_h2s (GM_h2hc (&msg->cid))); + send_broken_unknown (&msg->cid, &my_full_id, NULL, peer); + return GNUNET_OK; + } + + /* Is this a forward or backward ACK? + * Note: a poll should never be needed in a loopback case, + * since there is no possiblility of packet loss there, so + * this way of discerining FWD/BCK should not be a problem. + */ + id = GNUNET_PEER_search (peer); + if (GMP_get_short_id (get_next_hop (c)) == id) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD FC\n"); + fc = &c->fwd_fc; + } + else if (GMP_get_short_id (get_prev_hop (c)) == id) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK FC\n"); + fc = &c->bck_fc; + } + else + { + GNUNET_break_op (0); + return GNUNET_OK; + } + + pid = ntohl (msg->pid); + LOG (GNUNET_ERROR_TYPE_DEBUG, " PID %u, OLD %u\n", pid, fc->last_pid_recv); + fc->last_pid_recv = pid; + fwd = fc == &c->bck_fc; + GMC_send_ack (c, fwd, GNUNET_YES); + + return GNUNET_OK; +} + + +/** + * Send an ACK on the appropriate connection/channel, depending on + * the direction and the position of the peer. + * + * @param c Which connection to send the hop-by-hop ACK. + * @param fwd Is this a fwd ACK? (will go dest->root). + * @param force Send the ACK even if suboptimal (e.g. requested by POLL). + */ +void +GMC_send_ack (struct CadetConnection *c, int fwd, int force) +{ + unsigned int buffer; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "GMC send %s ACK on %s\n", + GM_f2s (fwd), GMC_2s (c)); + + if (NULL == c) + { + GNUNET_break (0); + return; + } + + if (GNUNET_NO != c->destroy) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " being destroyed, why bother...\n"); + return; + } + + /* Get available buffer space */ + if (GMC_is_terminal (c, fwd)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " getting from all channels\n"); + buffer = GMT_get_channels_buffer (c->t); + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " getting from one connection\n"); + buffer = GMC_get_buffer (c, fwd); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer available: %u\n", buffer); + if (0 == buffer && GNUNET_NO == force) + return; + + /* Send available buffer space */ + if (GMC_is_origin (c, fwd)) + { + GNUNET_assert (NULL != c->t); + LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channels...\n"); + GMT_unchoke_channels (c->t); + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on connection\n"); + send_ack (c, buffer, fwd, force); + } +} + + +/** + * Initialize the connections subsystem + * + * @param c Configuration handle. + */ +void +GMC_init (const struct GNUNET_CONFIGURATION_Handle *c) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_MSGS_QUEUE", + &max_msgs_queue)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + "CADET", "MAX_MSGS_QUEUE", "MISSING"); + GNUNET_SCHEDULER_shutdown (); + return; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_CONNECTIONS", + &max_connections)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + "CADET", "MAX_CONNECTIONS", "MISSING"); + GNUNET_SCHEDULER_shutdown (); + return; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (c, "CADET", "REFRESH_CONNECTION_TIME", + &refresh_connection_time)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + "CADET", "REFRESH_CONNECTION_TIME", "MISSING"); + GNUNET_SCHEDULER_shutdown (); + return; + } + create_connection_time = GNUNET_TIME_UNIT_SECONDS; + connections = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_NO); +} + + +/** + * Destroy each connection on shutdown. + * + * @param cls Closure (unused). + * @param key Current key code (CID, unused). + * @param value Value in the hash map (connection) + * + * @return #GNUNET_YES, because we should continue to iterate, + */ +static int +shutdown_iterator (void *cls, + const struct GNUNET_HashCode *key, + void *value) +{ + struct CadetConnection *c = value; + + GMC_destroy (c); + return GNUNET_YES; +} + + +/** + * Shut down the connections subsystem. + */ +void +GMC_shutdown (void) +{ + GNUNET_CONTAINER_multihashmap_iterate (connections, &shutdown_iterator, NULL); + GNUNET_CONTAINER_multihashmap_destroy (connections); + connections = NULL; +} + + +struct CadetConnection * +GMC_new (const struct GNUNET_CADET_Hash *cid, + struct CadetTunnel3 *t, + struct CadetPeerPath *p, + unsigned int own_pos) +{ + struct CadetConnection *c; + + c = GNUNET_new (struct CadetConnection); + c->id = *cid; + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (connections, + GMC_get_h (c), c, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + fc_init (&c->fwd_fc); + fc_init (&c->bck_fc); + c->fwd_fc.c = c; + c->bck_fc.c = c; + + c->t = t; + GNUNET_assert (own_pos <= p->length - 1); + c->own_pos = own_pos; + c->path = p; + p->c = c; + + if (GNUNET_OK != register_neighbors (c)) + { + if (0 == own_pos) + { + path_invalidate (c->path); + c->t = NULL; + c->path = NULL; + } + GMC_destroy (c); + return NULL; + } + + return c; +} + + +void +GMC_destroy (struct CadetConnection *c) +{ + if (NULL == c) + { + GNUNET_break (0); + return; + } + + if (2 == c->destroy) /* cancel queues -> GMP_queue_cancel -> q_destroy -> */ + return; /* -> message_sent -> GMC_destroy. Don't loop. */ + c->destroy = 2; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying connection %s\n", GMC_2s (c)); + LOG (GNUNET_ERROR_TYPE_DEBUG, " fc's f: %p, b: %p\n", + &c->fwd_fc, &c->bck_fc); + LOG (GNUNET_ERROR_TYPE_DEBUG, " fc tasks f: %u, b: %u\n", + c->fwd_fc.poll_task, c->bck_fc.poll_task); + + /* Cancel all traffic */ + if (NULL != c->path) + { + connection_cancel_queues (c, GNUNET_YES); + connection_cancel_queues (c, GNUNET_NO); + unregister_neighbors (c); + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, " fc tasks f: %u, b: %u\n", + c->fwd_fc.poll_task, c->bck_fc.poll_task); + + /* Cancel maintainance task (keepalive/timeout) */ + if (NULL != c->fwd_fc.poll_msg) + { + GMC_cancel (c->fwd_fc.poll_msg); + LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL msg FWD canceled\n"); + } + if (NULL != c->bck_fc.poll_msg) + { + GMC_cancel (c->bck_fc.poll_msg); + LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL msg BCK canceled\n"); + } + + /* Delete from tunnel */ + if (NULL != c->t) + GMT_remove_connection (c->t, c); + + if (GNUNET_NO == GMC_is_origin (c, GNUNET_YES) && NULL != c->path) + path_destroy (c->path); + if (GNUNET_SCHEDULER_NO_TASK != c->fwd_maintenance_task) + GNUNET_SCHEDULER_cancel (c->fwd_maintenance_task); + if (GNUNET_SCHEDULER_NO_TASK != c->bck_maintenance_task) + GNUNET_SCHEDULER_cancel (c->bck_maintenance_task); + if (GNUNET_SCHEDULER_NO_TASK != c->fwd_fc.poll_task) + { + GNUNET_SCHEDULER_cancel (c->fwd_fc.poll_task); + LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL FWD canceled\n"); + } + if (GNUNET_SCHEDULER_NO_TASK != c->bck_fc.poll_task) + { + GNUNET_SCHEDULER_cancel (c->bck_fc.poll_task); + LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL BCK canceled\n"); + } + + GNUNET_break (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (connections, + GMC_get_h (c), c)); + + GNUNET_STATISTICS_update (stats, "# connections", -1, GNUNET_NO); + GNUNET_free (c); +} + +/** + * Get the connection ID. + * + * @param c Connection to get the ID from. + * + * @return ID of the connection. + */ +const struct GNUNET_CADET_Hash * +GMC_get_id (const struct CadetConnection *c) +{ + return &c->id; +} + + +/** + * Get the connection ID. + * + * @param c Connection to get the ID from. + * + * @return ID of the connection. + */ +const struct GNUNET_HashCode * +GMC_get_h (const struct CadetConnection *c) +{ + return GM_h2hc (&c->id); +} + + +/** + * Get the connection path. + * + * @param c Connection to get the path from. + * + * @return path used by the connection. + */ +const struct CadetPeerPath * +GMC_get_path (const struct CadetConnection *c) +{ + if (GNUNET_NO == c->destroy) + return c->path; + return NULL; +} + + +/** + * Get the connection state. + * + * @param c Connection to get the state from. + * + * @return state of the connection. + */ +enum CadetConnectionState +GMC_get_state (const struct CadetConnection *c) +{ + return c->state; +} + +/** + * Get the connection tunnel. + * + * @param c Connection to get the tunnel from. + * + * @return tunnel of the connection. + */ +struct CadetTunnel3 * +GMC_get_tunnel (const struct CadetConnection *c) +{ + return c->t; +} + + +/** + * Get free buffer space in a connection. + * + * @param c Connection. + * @param fwd Is query about FWD traffic? + * + * @return Free buffer space [0 - max_msgs_queue/max_connections] + */ +unsigned int +GMC_get_buffer (struct CadetConnection *c, int fwd) +{ + struct CadetFlowControl *fc; + + fc = fwd ? &c->fwd_fc : &c->bck_fc; + + return (fc->queue_max - fc->queue_n); +} + +/** + * Get how many messages have we allowed to send to us from a direction. + * + * @param c Connection. + * @param fwd Are we asking about traffic from FWD (BCK messages)? + * + * @return last_ack_sent - last_pid_recv + */ +unsigned int +GMC_get_allowed (struct CadetConnection *c, int fwd) +{ + struct CadetFlowControl *fc; + + fc = fwd ? &c->fwd_fc : &c->bck_fc; + if (GM_is_pid_bigger(fc->last_pid_recv, fc->last_ack_sent)) + { + return 0; + } + return (fc->last_ack_sent - fc->last_pid_recv); +} + +/** + * Get messages queued in a connection. + * + * @param c Connection. + * @param fwd Is query about FWD traffic? + * + * @return Number of messages queued. + */ +unsigned int +GMC_get_qn (struct CadetConnection *c, int fwd) +{ + struct CadetFlowControl *fc; + + fc = fwd ? &c->fwd_fc : &c->bck_fc; + + return fc->queue_n; +} + + +/** + * Get next PID to use. + * + * @param c Connection. + * @param fwd Is query about FWD traffic? + * + * @return Last PID used + 1. + */ +unsigned int +GMC_get_pid (struct CadetConnection *c, int fwd) +{ + struct CadetFlowControl *fc; + + fc = fwd ? &c->fwd_fc : &c->bck_fc; + + return fc->last_pid_sent + 1; +} + + +/** + * Allow the connection to advertise a buffer of the given size. + * + * The connection will send an @c fwd ACK message (so: in direction !fwd) + * allowing up to last_pid_recv + buffer. + * + * @param c Connection. + * @param buffer How many more messages the connection can accept. + * @param fwd Is this about FWD traffic? (The ack will go dest->root). + */ +void +GMC_allow (struct CadetConnection *c, unsigned int buffer, int fwd) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, " allowing %s %u messages %s\n", + GMC_2s (c), buffer, GM_f2s (fwd)); + send_ack (c, buffer, fwd, GNUNET_NO); +} + + +/** + * Notify other peers on a connection of a broken link. Mark connections + * to destroy after all traffic has been sent. + * + * @param c Connection on which there has been a disconnection. + * @param peer Peer that disconnected. + */ +void +GMC_notify_broken (struct CadetConnection *c, + struct CadetPeer *peer) +{ + int fwd; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + " notify broken on %s due to %s disconnect\n", + GMC_2s (c), GMP_2s (peer)); + + fwd = peer == get_prev_hop (c); + + if (GNUNET_YES == GMC_is_terminal (c, fwd)) + { + /* Local shutdown, no one to notify about this. */ + GMC_destroy (c); + return; + } + if (GNUNET_NO == c->destroy) + send_broken (c, &my_full_id, GMP_get_id (peer), fwd); + + /* Connection will have at least one pending message + * (the one we just scheduled), so no point in checking whether to + * destroy immediately. */ + c->destroy = GNUNET_YES; + c->state = CADET_CONNECTION_DESTROYED; + + /** + * Cancel all queues, if no message is left, connection will be destroyed. + */ + connection_cancel_queues (c, !fwd); + + return; +} + + +/** + * Is this peer the first one on the connection? + * + * @param c Connection. + * @param fwd Is this about fwd traffic? + * + * @return #GNUNET_YES if origin, #GNUNET_NO if relay/terminal. + */ +int +GMC_is_origin (struct CadetConnection *c, int fwd) +{ + if (!fwd && c->path->length - 1 == c->own_pos ) + return GNUNET_YES; + if (fwd && 0 == c->own_pos) + return GNUNET_YES; + return GNUNET_NO; +} + + +/** + * Is this peer the last one on the connection? + * + * @param c Connection. + * @param fwd Is this about fwd traffic? + * Note that the ROOT is the terminal for BCK traffic! + * + * @return #GNUNET_YES if terminal, #GNUNET_NO if relay/origin. + */ +int +GMC_is_terminal (struct CadetConnection *c, int fwd) +{ + return GMC_is_origin (c, !fwd); +} + + +/** + * See if we are allowed to send by the next hop in the given direction. + * + * @param c Connection. + * @param fwd Is this about fwd traffic? + * + * @return #GNUNET_YES in case it's OK to send. + */ +int +GMC_is_sendable (struct CadetConnection *c, int fwd) +{ + struct CadetFlowControl *fc; + + LOG (GNUNET_ERROR_TYPE_DEBUG, " checking sendability of %s traffic on %s\n", + GM_f2s (fwd), GMC_2s (c)); + if (NULL == c) + { + GNUNET_break (0); + return GNUNET_YES; + } + fc = fwd ? &c->fwd_fc : &c->bck_fc; + LOG (GNUNET_ERROR_TYPE_DEBUG, + " last ack recv: %u, last pid sent: %u\n", + fc->last_ack_recv, fc->last_pid_sent); + if (GM_is_pid_bigger (fc->last_ack_recv, fc->last_pid_sent)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " sendable\n"); + return GNUNET_YES; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " not sendable\n"); + return GNUNET_NO; +} + + +/** + * Check if this connection is a direct one (never trim a direct connection). + * + * @param c Connection. + * + * @return #GNUNET_YES in case it's a direct connection, #GNUNET_NO otherwise. + */ +int +GMC_is_direct (struct CadetConnection *c) +{ + return (c->path->length == 2) ? GNUNET_YES : GNUNET_NO; +} + +/** + * Sends an already built message on a connection, properly registering + * all used resources. + * + * @param message Message to send. Function makes a copy of it. + * If message is not hop-by-hop, decrements TTL of copy. + * @param payload_type Type of payload, in case the message is encrypted. + * @param c Connection on which this message is transmitted. + * @param fwd Is this a fwd message? + * @param force Force the connection to accept the message (buffer overfill). + * @param cont Continuation called once message is sent. Can be NULL. + * @param cont_cls Closure for @c cont. + * + * @return Handle to cancel the message before it's sent. + * NULL on error or if @c cont is NULL. + * Invalid on @c cont call. + */ +struct CadetConnectionQueue * +GMC_send_prebuilt_message (const struct GNUNET_MessageHeader *message, + uint16_t payload_type, uint32_t payload_id, + struct CadetConnection *c, int fwd, int force, + GMC_sent cont, void *cont_cls) +{ + struct CadetFlowControl *fc; + struct CadetConnectionQueue *q; + void *data; + size_t size; + uint16_t type; + int droppable; + + size = ntohs (message->size); + data = GNUNET_malloc (size); + memcpy (data, message, size); + type = ntohs (message->type); + LOG (GNUNET_ERROR_TYPE_INFO, "--> %s (%s %u) on connection %s (%u bytes)\n", + GM_m2s (type), GM_m2s (payload_type), payload_id, GMC_2s (c), size); + + fc = fwd ? &c->fwd_fc : &c->bck_fc; + droppable = GNUNET_NO == force; + switch (type) + { + struct GNUNET_CADET_Encrypted *emsg; + struct GNUNET_CADET_KX *kmsg; + struct GNUNET_CADET_ACK *amsg; + struct GNUNET_CADET_Poll *pmsg; + struct GNUNET_CADET_ConnectionDestroy *dmsg; + struct GNUNET_CADET_ConnectionBroken *bmsg; + uint32_t ttl; + + case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED: + emsg = (struct GNUNET_CADET_Encrypted *) data; + ttl = ntohl (emsg->ttl); + if (0 == ttl) + { + GNUNET_break_op (0); + GNUNET_free (data); + return NULL; + } + emsg->cid = c->id; + emsg->ttl = htonl (ttl - 1); + emsg->pid = htonl (0); + LOG (GNUNET_ERROR_TYPE_DEBUG, " Q_N+ %p %u\n", fc, fc->queue_n); + LOG (GNUNET_ERROR_TYPE_DEBUG, "last pid sent %u\n", fc->last_pid_sent); + LOG (GNUNET_ERROR_TYPE_DEBUG, " ack recv %u\n", fc->last_ack_recv); + if (GNUNET_YES == droppable) + { + fc->queue_n++; + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " not droppable, Q_N stays the same\n"); + } + if (GM_is_pid_bigger (fc->last_pid_sent + 1, fc->last_ack_recv)) + { + GMC_start_poll (c, fwd); + } + break; + + case GNUNET_MESSAGE_TYPE_CADET_KX: + kmsg = (struct GNUNET_CADET_KX *) data; + kmsg->cid = c->id; + break; + + case GNUNET_MESSAGE_TYPE_CADET_ACK: + amsg = (struct GNUNET_CADET_ACK *) data; + amsg->cid = c->id; + LOG (GNUNET_ERROR_TYPE_DEBUG, " ack %u\n", ntohl (amsg->ack)); + droppable = GNUNET_NO; + break; + + case GNUNET_MESSAGE_TYPE_CADET_POLL: + pmsg = (struct GNUNET_CADET_Poll *) data; + pmsg->cid = c->id; + LOG (GNUNET_ERROR_TYPE_DEBUG, " poll %u\n", ntohl (pmsg->pid)); + droppable = GNUNET_NO; + break; + + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY: + dmsg = (struct GNUNET_CADET_ConnectionDestroy *) data; + dmsg->cid = c->id; + break; + + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN: + bmsg = (struct GNUNET_CADET_ConnectionBroken *) data; + bmsg->cid = c->id; + break; + + case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE: + GNUNET_break (0); + /* falltrough */ + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE: + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK: + break; + + default: + GNUNET_break (0); + GNUNET_free (data); + return NULL; + } + + if (fc->queue_n > fc->queue_max && droppable) + { + GNUNET_STATISTICS_update (stats, "# messages dropped (buffer full)", + 1, GNUNET_NO); + GNUNET_break (0); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "queue full: %u/%u\n", + fc->queue_n, fc->queue_max); + if (GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED == type) + { + fc->queue_n--; + } + GNUNET_free (data); + return NULL; /* Drop this message */ + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %p %u\n", c, c->pending_messages); +// c->pending_messages++; + + q = GNUNET_new (struct CadetConnectionQueue); + q->forced = !droppable; + q->q = GMP_queue_add (get_hop (c, fwd), data, type, payload_type, payload_id, + size, c, fwd, &conn_message_sent, q); + if (NULL == q->q) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING dropping msg on %s\n", GMC_2s (c)); + GNUNET_free (data); + GNUNET_free (q); + return NULL; + } + q->cont = cont; + q->cont_cls = cont_cls; + return (NULL == cont) ? NULL : q; +} + + +/** + * Cancel a previously sent message while it's in the queue. + * + * ONLY can be called before the continuation given to the send function + * is called. Once the continuation is called, the message is no longer in the + * queue. + * + * @param q Handle to the queue. + */ +void +GMC_cancel (struct CadetConnectionQueue *q) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, "! GMC cancel message\n"); + + /* queue destroy calls message_sent, which calls q->cont and frees q */ + GMP_queue_destroy (q->q, GNUNET_YES, GNUNET_NO, 0); +} + + +/** + * Sends a CREATE CONNECTION message for a path to a peer. + * Changes the connection and tunnel states if necessary. + * + * @param connection Connection to create. + */ +void +GMC_send_create (struct CadetConnection *connection) +{ + enum CadetTunnel3CState state; + size_t size; + + size = sizeof (struct GNUNET_CADET_ConnectionCreate); + size += connection->path->length * sizeof (struct GNUNET_PeerIdentity); + + LOG (GNUNET_ERROR_TYPE_INFO, "===> %s on connection %s (%u bytes)\n", + GM_m2s (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE), + GMC_2s (connection), size); + LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %p %u (create)\n", + connection, connection->pending_messages); + connection->pending_messages++; + + connection->maintenance_q = + GMP_queue_add (get_next_hop (connection), NULL, + GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, + GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, 0, + size, connection, GNUNET_YES, &conn_message_sent, NULL); + + state = GMT_get_cstate (connection->t); + if (CADET_TUNNEL3_SEARCHING == state || CADET_TUNNEL3_NEW == state) + GMT_change_cstate (connection->t, CADET_TUNNEL3_WAITING); + if (CADET_CONNECTION_NEW == connection->state) + connection_change_state (connection, CADET_CONNECTION_SENT); +} + + +/** + * Send a message to all peers in this connection that the connection + * is no longer valid. + * + * If some peer should not receive the message, it should be zero'ed out + * before calling this function. + * + * @param c The connection whose peers to notify. + */ +void +GMC_send_destroy (struct CadetConnection *c) +{ + struct GNUNET_CADET_ConnectionDestroy msg; + + if (GNUNET_YES == c->destroy) + return; + + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);; + msg.cid = c->id; + LOG (GNUNET_ERROR_TYPE_DEBUG, + " sending connection destroy for connection %s\n", + GMC_2s (c)); + + if (GNUNET_NO == GMC_is_terminal (c, GNUNET_YES)) + GMC_send_prebuilt_message (&msg.header, + GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY, 0, + c, GNUNET_YES, GNUNET_YES, NULL, NULL); + if (GNUNET_NO == GMC_is_terminal (c, GNUNET_NO)) + GMC_send_prebuilt_message (&msg.header, + GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY, 0, + c, GNUNET_NO, GNUNET_YES, NULL, NULL); + c->destroy = GNUNET_YES; + c->state = CADET_CONNECTION_DESTROYED; +} + + +/** + * @brief Start a polling timer for the connection. + * + * When a neighbor does not accept more traffic on the connection it could be + * caused by a simple congestion or by a lost ACK. Polling enables to check + * for the lastest ACK status for a connection. + * + * @param c Connection. + * @param fwd Should we poll in the FWD direction? + */ +void +GMC_start_poll (struct CadetConnection *c, int fwd) +{ + struct CadetFlowControl *fc; + + fc = fwd ? &c->fwd_fc : &c->bck_fc; + LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL %s requested\n", + GM_f2s (fwd)); + if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task || NULL != fc->poll_msg) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " *** not needed (%u, %p)\n", + fc->poll_task, fc->poll_msg); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL started on request\n"); + fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time, + &connection_poll, + fc); +} + + +/** + * @brief Stop polling a connection for ACKs. + * + * Once we have enough ACKs for future traffic, polls are no longer necessary. + * + * @param c Connection. + * @param fwd Should we stop the poll in the FWD direction? + */ +void +GMC_stop_poll (struct CadetConnection *c, int fwd) +{ + struct CadetFlowControl *fc; + + fc = fwd ? &c->fwd_fc : &c->bck_fc; + if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task) + { + GNUNET_SCHEDULER_cancel (fc->poll_task); + fc->poll_task = GNUNET_SCHEDULER_NO_TASK; + } +} + +/** + * Get a (static) string for a connection. + * + * @param c Connection. + */ +const char * +GMC_2s (const struct CadetConnection *c) +{ + if (NULL == c) + return "NULL"; + + if (NULL != c->t) + { + static char buf[128]; + + sprintf (buf, "%s (->%s)", + GNUNET_h2s (GM_h2hc (GMC_get_id (c))), GMT_2s (c->t)); + return buf; + } + return GNUNET_h2s (GM_h2hc (&c->id)); +} diff --git a/src/cadet/gnunet-service-cadet_connection.h b/src/cadet/gnunet-service-cadet_connection.h new file mode 100644 index 000000000..4e1104c2b --- /dev/null +++ b/src/cadet/gnunet-service-cadet_connection.h @@ -0,0 +1,566 @@ +/* + This file is part of GNUnet. + (C) 2013 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 cadet/gnunet-service-cadet_connection.h + * @brief cadet service; dealing with connections + * @author Bartlomiej Polot + * + * All functions in this file should use the prefix GMC (Gnunet Cadet Connection) + */ + +#ifndef GNUNET_SERVICE_CADET_CONNECTION_H +#define GNUNET_SERVICE_CADET_CONNECTION_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_util_lib.h" + + +/** + * All the states a connection can be in. + */ +enum CadetConnectionState +{ + /** + * Uninitialized status, should never appear in operation. + */ + CADET_CONNECTION_NEW, + + /** + * Connection create message sent, waiting for ACK. + */ + CADET_CONNECTION_SENT, + + /** + * Connection ACK sent, waiting for ACK. + */ + CADET_CONNECTION_ACK, + + /** + * Connection confirmed, ready to carry traffic. + */ + CADET_CONNECTION_READY, + + /** + * Connection to be destroyed, just waiting to empty queues. + */ + CADET_CONNECTION_DESTROYED, +}; + + +/** + * Struct containing all information regarding a connection to a peer. + */ +struct CadetConnection; + +/** + * Handle for messages queued but not yet sent. + */ +struct CadetConnectionQueue; + +#include "cadet_path.h" +#include "gnunet-service-cadet_channel.h" +#include "gnunet-service-cadet_peer.h" + + + +/** + * Callback called when a queued message is sent. + * + * @param cls Closure. + * @param c Connection this message was on. + * @param type Type of message sent. + * @param fwd Was this a FWD going message? + * @param size Size of the message. + */ +typedef void (*GMC_sent) (void *cls, + struct CadetConnection *c, + struct CadetConnectionQueue *q, + uint16_t type, int fwd, size_t size); + +/** + * Core handler for connection creation. + * + * @param cls Closure (unused). + * @param peer Sender (neighbor). + * @param message Message. + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +GMC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message); + +/** + * Core handler for path confirmations. + * + * @param cls closure + * @param message message + * @param peer peer identity this notification is about + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +GMC_handle_confirm (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message); + +/** + * Core handler for notifications of broken paths + * + * @param cls Closure (unused). + * @param id Peer identity of sending neighbor. + * @param message Message. + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +GMC_handle_broken (void* cls, + const struct GNUNET_PeerIdentity* id, + const struct GNUNET_MessageHeader* message); + +/** + * Core handler for tunnel destruction + * + * @param cls Closure (unused). + * @param peer Peer identity of sending neighbor. + * @param message Message. + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +GMC_handle_destroy (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message); + +/** + * Core handler for encrypted cadet network traffic (channel mgmt, data). + * + * @param cls Closure (unused). + * @param message Message received. + * @param peer Peer who sent the message. + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +GMC_handle_encrypted (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message); + +/** + * Core handler for key exchange traffic (ephemeral key, ping, pong). + * + * @param cls Closure (unused). + * @param message Message received. + * @param peer Peer who sent the message. + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +GMC_handle_kx (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message); + +/** + * Core handler for cadet network traffic point-to-point acks. + * + * @param cls closure + * @param message message + * @param peer peer identity this notification is about + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +GMC_handle_ack (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message); + +/** + * Core handler for cadet network traffic point-to-point ack polls. + * + * @param cls closure + * @param message message + * @param peer peer identity this notification is about + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +GMC_handle_poll (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message); + +/** + * Core handler for cadet keepalives. + * + * @param cls closure + * @param message message + * @param peer peer identity this notification is about + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + * + * TODO: Check who we got this from, to validate route. + */ +int +GMC_handle_keepalive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message); + +/** + * Send an ACK on the appropriate connection/channel, depending on + * the direction and the position of the peer. + * + * @param c Which connection to send the hop-by-hop ACK. + * @param fwd Is this a fwd ACK? (will go dest->root). + * @param force Send the ACK even if suboptimal (e.g. requested by POLL). + */ +void +GMC_send_ack (struct CadetConnection *c, int fwd, int force); + +/** + * Initialize the connections subsystem + * + * @param c Configuration handle. + */ +void +GMC_init (const struct GNUNET_CONFIGURATION_Handle *c); + +/** + * Shut down the connections subsystem. + */ +void +GMC_shutdown (void); + +/** + * Create a connection. + * + * @param cid Connection ID (either created locally or imposed remotely). + * @param t Tunnel this connection belongs to (or NULL); + * @param p Path this connection has to use. + * @param own_pos Own position in the @c p path. + * + * @return Newly created connection, NULL in case of error (own id not in path). + */ +struct CadetConnection * +GMC_new (const struct GNUNET_CADET_Hash *cid, + struct CadetTunnel3 *t, + struct CadetPeerPath *p, + unsigned int own_pos); + +/** + * Connection is no longer needed: destroy it. + * + * Cancels all pending traffic (including possible DESTROY messages), all + * maintenance tasks and removes the connection from neighbor peers and tunnel. + * + * @param c Connection to destroy. + */ +void +GMC_destroy (struct CadetConnection *c); + +/** + * Get the connection ID. + * + * @param c Connection to get the ID from. + * + * @return ID of the connection. + */ +const struct GNUNET_CADET_Hash * +GMC_get_id (const struct CadetConnection *c); + + +/** + * Get a hash for the connection ID. + * + * @param c Connection to get the hash. + * + * @return Hash expanded from the ID of the connection. + */ +const struct GNUNET_HashCode * +GMC_get_h (const struct CadetConnection *c); + + +/** + * Get the connection path. + * + * @param c Connection to get the path from. + * + * @return path used by the connection. + */ +const struct CadetPeerPath * +GMC_get_path (const struct CadetConnection *c); + +/** + * Get the connection state. + * + * @param c Connection to get the state from. + * + * @return state of the connection. + */ +enum CadetConnectionState +GMC_get_state (const struct CadetConnection *c); + +/** + * Get the connection tunnel. + * + * @param c Connection to get the tunnel from. + * + * @return tunnel of the connection. + */ +struct CadetTunnel3 * +GMC_get_tunnel (const struct CadetConnection *c); + +/** + * Get free buffer space in a connection. + * + * @param c Connection. + * @param fwd Is query about FWD traffic? + * + * @return Free buffer space [0 - max_msgs_queue/max_connections] + */ +unsigned int +GMC_get_buffer (struct CadetConnection *c, int fwd); + +/** + * Get how many messages have we allowed to send to us from a direction. + * + * @param c Connection. + * @param fwd Are we asking about traffic from FWD (BCK messages)? + * + * @return last_ack_sent - last_pid_recv + */ +unsigned int +GMC_get_allowed (struct CadetConnection *c, int fwd); + +/** + * Get messages queued in a connection. + * + * @param c Connection. + * @param fwd Is query about FWD traffic? + * + * @return Number of messages queued. + */ +unsigned int +GMC_get_qn (struct CadetConnection *c, int fwd); + +/** + * Get next PID to use. + * + * @param c Connection. + * @param fwd Is query about FWD traffic? + * + * @return Last PID used + 1. + */ +unsigned int +GMC_get_pid (struct CadetConnection *c, int fwd); + +/** + * Allow the connection to advertise a buffer of the given size. + * + * The connection will send an @c fwd ACK message (so: in direction !fwd) + * allowing up to last_pid_recv + buffer. + * + * @param c Connection. + * @param buffer How many more messages the connection can accept. + * @param fwd Is this about FWD traffic? (The ack will go dest->root). + */ +void +GMC_allow (struct CadetConnection *c, unsigned int buffer, int fwd); + +/** + * Send FWD keepalive packets for a connection. + * + * @param cls Closure (connection for which to send the keepalive). + * @param tc Notification context. + */ +void +GMC_fwd_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * Send BCK keepalive packets for a connection. + * + * @param cls Closure (connection for which to send the keepalive). + * @param tc Notification context. + */ +void +GMC_bck_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Notify other peers on a connection of a broken link. Mark connections + * to destroy after all traffic has been sent. + * + * @param c Connection on which there has been a disconnection. + * @param peer Peer that disconnected. + */ +void +GMC_notify_broken (struct CadetConnection *c, + struct CadetPeer *peer); + +/** + * Is this peer the first one on the connection? + * + * @param c Connection. + * @param fwd Is this about fwd traffic? + * + * @return #GNUNET_YES if origin, #GNUNET_NO if relay/terminal. + */ +int +GMC_is_origin (struct CadetConnection *c, int fwd); + +/** + * Is this peer the last one on the connection? + * + * @param c Connection. + * @param fwd Is this about fwd traffic? + * Note that the ROOT is the terminal for BCK traffic! + * + * @return #GNUNET_YES if terminal, #GNUNET_NO if relay/origin. + */ +int +GMC_is_terminal (struct CadetConnection *c, int fwd); + +/** + * See if we are allowed to send by the next hop in the given direction. + * + * @param c Connection. + * @param fwd Is this about fwd traffic? + * + * @return #GNUNET_YES in case it's OK to send. + */ +int +GMC_is_sendable (struct CadetConnection *c, int fwd); + +/** + * Check if this connection is a direct one (never trim a direct connection). + * + * @param c Connection. + * + * @return #GNUNET_YES in case it's a direct connection, #GNUNET_NO otherwise. + */ +int +GMC_is_direct (struct CadetConnection *c); + +/** + * Cancel a previously sent message while it's in the queue. + * + * ONLY can be called before the continuation given to the send function + * is called. Once the continuation is called, the message is no longer in the + * queue. + * + * @param q Handle to the queue. + */ +void +GMC_cancel (struct CadetConnectionQueue *q); + +/** + * Sends an already built message on a connection, properly registering + * all used resources. + * + * @param message Message to send. Function makes a copy of it. + * If message is not hop-by-hop, decrements TTL of copy. + * @param payload_type Type of payload, in case the message is encrypted. + * @param c Connection on which this message is transmitted. + * @param fwd Is this a fwd message? + * @param force Force the connection to accept the message (buffer overfill). + * @param cont Continuation called once message is sent. Can be NULL. + * @param cont_cls Closure for @c cont. + * + * @return Handle to cancel the message before it's sent. + * NULL on error or if @c cont is NULL. + * Invalid on @c cont call. + */ +struct CadetConnectionQueue * +GMC_send_prebuilt_message (const struct GNUNET_MessageHeader *message, + uint16_t payload_type, uint32_t payload_id, + struct CadetConnection *c, int fwd, int force, + GMC_sent cont, void *cont_cls); + +/** + * Sends a CREATE CONNECTION message for a path to a peer. + * Changes the connection and tunnel states if necessary. + * + * @param connection Connection to create. + */ +void +GMC_send_create (struct CadetConnection *connection); + +/** + * Send a message to all peers in this connection that the connection + * is no longer valid. + * + * If some peer should not receive the message, it should be zero'ed out + * before calling this function. + * + * @param c The connection whose peers to notify. + */ +void +GMC_send_destroy (struct CadetConnection *c); + +/** + * @brief Start a polling timer for the connection. + * + * When a neighbor does not accept more traffic on the connection it could be + * caused by a simple congestion or by a lost ACK. Polling enables to check + * for the lastest ACK status for a connection. + * + * @param c Connection. + * @param fwd Should we poll in the FWD direction? + */ +void +GMC_start_poll (struct CadetConnection *c, int fwd); + + +/** + * @brief Stop polling a connection for ACKs. + * + * Once we have enough ACKs for future traffic, polls are no longer necessary. + * + * @param c Connection. + * @param fwd Should we stop the poll in the FWD direction? + */ +void +GMC_stop_poll (struct CadetConnection *c, int fwd); + +/** + * Get a (static) string for a connection. + * + * @param c Connection. + */ +const char * +GMC_2s (const struct CadetConnection *c); + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_SERVICE_CADET_CONNECTION_H */ +#endif +/* end of gnunet-service-cadet_connection.h */ diff --git a/src/cadet/gnunet-service-cadet_dht.c b/src/cadet/gnunet-service-cadet_dht.c new file mode 100644 index 000000000..b187e3cd9 --- /dev/null +++ b/src/cadet/gnunet-service-cadet_dht.c @@ -0,0 +1,423 @@ +/* + This file is part of GNUnet. + (C) 2013 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_util_lib.h" + +#include "gnunet_dht_service.h" +#include "gnunet_statistics_service.h" + +#include "cadet_path.h" +#include "gnunet-service-cadet_dht.h" +#include "gnunet-service-cadet_peer.h" +#include "gnunet-service-cadet_hello.h" + +#define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__) + + +/******************************************************************************/ +/******************************** STRUCTS **********************************/ +/******************************************************************************/ + +/** + * Handle for DHT searches. + */ +struct GMD_search_handle +{ + /** DHT_GET handle. */ + struct GNUNET_DHT_GetHandle *dhtget; + + /** Provided callback to call when a path is found. */ + GMD_search_callback callback; + + /** Provided closure. */ + void *cls; + + /** Peer ID searched for */ + GNUNET_PEER_Id peer_id; +}; + + +/******************************************************************************/ +/******************************* GLOBALS ***********************************/ +/******************************************************************************/ + +/** + * Global handle to the statistics service. + */ +extern struct GNUNET_STATISTICS_Handle *stats; + +/** + * Own ID (short value). + */ +extern GNUNET_PEER_Id myid; + +/** + * Own ID (full value). + */ +extern struct GNUNET_PeerIdentity my_full_id; + +/** + * Handle to use DHT. + */ +static struct GNUNET_DHT_Handle *dht_handle; + +/** + * How often to PUT own ID in the DHT. + */ +static struct GNUNET_TIME_Relative id_announce_time; + +/** + * DHT replication level, see DHT API: GNUNET_DHT_get_start, GNUNET_DHT_put. + */ +static unsigned long long dht_replication_level; + +/** + * Task to periodically announce itself in the network. + */ +static GNUNET_SCHEDULER_TaskIdentifier announce_id_task; + +/** + * GET requests to stop on shutdown. + */ +static struct GNUNET_CONTAINER_MultiHashMap32 *get_requests; + +/******************************************************************************/ +/******************************** STATIC ***********************************/ +/******************************************************************************/ + + +/** + * Build a PeerPath from the paths returned from the DHT, reversing the paths + * to obtain a local peer -> destination path and interning the peer ids. + * + * @return Newly allocated and created path + * + * FIXME refactor and use build_path_from_peer_ids + */ +static struct CadetPeerPath * +path_build_from_dht (const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length) +{ + struct CadetPeerPath *p; + GNUNET_PEER_Id id; + int i; + + p = path_new (1); + p->peers[0] = myid; + GNUNET_PEER_change_rc (myid, 1); + i = get_path_length; + LOG (GNUNET_ERROR_TYPE_DEBUG, " GET has %d hops.\n", i); + for (i--; i >= 0; i--) + { + id = GNUNET_PEER_intern (&get_path[i]); + if (p->length > 0 && id == p->peers[p->length - 1]) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n"); + GNUNET_PEER_change_rc (id, -1); + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " Adding from GET: %s.\n", + GNUNET_i2s (&get_path[i])); + p->length++; + p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length); + p->peers[p->length - 1] = id; + } + } + i = put_path_length; + LOG (GNUNET_ERROR_TYPE_DEBUG, " PUT has %d hops.\n", i); + for (i--; i >= 0; i--) + { + id = GNUNET_PEER_intern (&put_path[i]); + if (id == myid) + { + /* PUT path went through us, so discard the path up until now and start + * from here to get a much shorter (and loop-free) path. + */ + path_destroy (p); + p = path_new (0); + } + if (p->length > 0 && id == p->peers[p->length - 1]) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n"); + GNUNET_PEER_change_rc (id, -1); + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " Adding from PUT: %s.\n", + GNUNET_i2s (&put_path[i])); + p->length++; + p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length); + p->peers[p->length - 1] = id; + } + } +#if CADET_DEBUG + if (get_path_length > 0) + LOG (GNUNET_ERROR_TYPE_DEBUG, " (first of GET: %s)\n", + GNUNET_i2s (&get_path[0])); + if (put_path_length > 0) + LOG (GNUNET_ERROR_TYPE_DEBUG, " (first of PUT: %s)\n", + GNUNET_i2s (&put_path[0])); + LOG (GNUNET_ERROR_TYPE_DEBUG, " In total: %d hops\n", + p->length); + for (i = 0; i < p->length; i++) + { + struct GNUNET_PeerIdentity peer_id; + + GNUNET_PEER_resolve (p->peers[i], &peer_id); + LOG (GNUNET_ERROR_TYPE_DEBUG, " %u: %s\n", p->peers[i], + GNUNET_i2s (&peer_id)); + } +#endif + return p; +} + + +/** + * Function to process paths received for a new peer addition. The recorded + * paths form the initial tunnel, which can be optimized later. + * Called on each result obtained for the DHT search. + * + * @param cls closure + * @param exp when will this value expire + * @param key key of the result + * @param get_path path of the get request + * @param get_path_length lenght of get_path + * @param put_path path of the put request + * @param put_path_length length of the put_path + * @param type type of the result + * @param size number of bytes in data + * @param data pointer to the result data + */ +static void +dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp, + const struct GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length, enum GNUNET_BLOCK_Type type, + size_t size, const void *data) +{ + struct GMD_search_handle *h = cls; + struct GNUNET_HELLO_Message *hello; + struct CadetPeerPath *p; + struct CadetPeer *peer; + char *s; + + p = path_build_from_dht (get_path, get_path_length, + put_path, put_path_length); + s = path_2s (p); + LOG (GNUNET_ERROR_TYPE_INFO, "Got path from DHT: %s\n", s); + GNUNET_free_non_null (s); + peer = GMP_get_short (p->peers[p->length - 1]); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Got HELLO for %s\n", GMP_2s (peer)); + h->callback (h->cls, p); + path_destroy (p); + hello = (struct GNUNET_HELLO_Message *) data; + GMP_set_hello (peer, hello); + GMP_try_connect (peer); + return; +} + + +/** + * Periodically announce self id in the DHT + * + * @param cls closure + * @param tc task context + */ +static void +announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_HashCode phash; + const struct GNUNET_HELLO_Message *hello; + size_t size; + struct GNUNET_TIME_Absolute expiration; + struct GNUNET_TIME_Relative retry_time; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + { + announce_id_task = GNUNET_SCHEDULER_NO_TASK; + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "Announce ID\n"); + + /* TODO + * - Set data expiration in function of X + * - Adapt X to churn + */ + hello = GMH_get_mine (); + if (NULL == hello || (size = GNUNET_HELLO_size (hello)) == 0) + { + /* Peerinfo gave us no hello yet, try again in a second. */ + announce_id_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &announce_id, cls); + LOG (GNUNET_ERROR_TYPE_DEBUG, " no hello, waiting!\n"); + return; + } + expiration = GNUNET_HELLO_get_last_expiration (hello); + retry_time = GNUNET_TIME_absolute_get_remaining (expiration); + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Hello %p size: %u\n", hello, size); + memset (&phash, 0, sizeof (phash)); + memcpy (&phash, &my_full_id, sizeof (my_full_id)); + GNUNET_DHT_put (dht_handle, /* DHT handle */ + &phash, /* Key to use */ + dht_replication_level, /* Replication level */ + GNUNET_DHT_RO_RECORD_ROUTE + | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */ + GNUNET_BLOCK_TYPE_DHT_HELLO, /* Block type */ + size, /* Size of the data */ + (const char *) hello, /* Data itself */ + expiration, /* Data expiration */ + retry_time, /* Retry time */ + NULL, /* Continuation */ + NULL); /* Continuation closure */ + announce_id_task = + GNUNET_SCHEDULER_add_delayed (id_announce_time, &announce_id, cls); +} + +/** + * Iterator over hash map entries and stop GET requests before disconnecting + * from the DHT. + * + * @param cls Closure (unused) + * @param key Current peer ID. + * @param value Value in the hash map (GMD_search_handle). + * + * @return #GNUNET_YES, we should continue to iterate, + */ +int +stop_get (void *cls, + uint32_t key, + void *value) +{ + struct GMD_search_handle *h = value; + + GMD_search_stop (h); + return GNUNET_YES; +} + + +/******************************************************************************/ +/******************************** API ***********************************/ +/******************************************************************************/ + +/** + * Initialize the DHT subsystem. + * + * @param c Configuration. + */ +void +GMD_init (const struct GNUNET_CONFIGURATION_Handle *c) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (c, "CADET", "DHT_REPLICATION_LEVEL", + &dht_replication_level)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, + "CADET", "DHT_REPLICATION_LEVEL", "USING DEFAULT"); + dht_replication_level = 3; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (c, "CADET", "ID_ANNOUNCE_TIME", + &id_announce_time)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + "CADET", "ID_ANNOUNCE_TIME", "MISSING"); + GNUNET_SCHEDULER_shutdown (); + return; + } + + dht_handle = GNUNET_DHT_connect (c, 64); + if (NULL == dht_handle) + { + GNUNET_break (0); + } + + announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL); + get_requests = GNUNET_CONTAINER_multihashmap32_create (32); +} + + +/** + * Shut down the DHT subsystem. + */ +void +GMD_shutdown (void) +{ + GNUNET_CONTAINER_multihashmap32_iterate (get_requests, &stop_get, NULL); + GNUNET_CONTAINER_multihashmap32_destroy (get_requests); + if (dht_handle != NULL) + { + GNUNET_DHT_disconnect (dht_handle); + dht_handle = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != announce_id_task) + { + GNUNET_SCHEDULER_cancel (announce_id_task); + announce_id_task = GNUNET_SCHEDULER_NO_TASK; + } +} + +struct GMD_search_handle * +GMD_search (const struct GNUNET_PeerIdentity *peer_id, + GMD_search_callback callback, void *cls) +{ + struct GNUNET_HashCode phash; + struct GMD_search_handle *h; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + " Starting DHT GET for peer %s\n", GNUNET_i2s (peer_id)); + memset (&phash, 0, sizeof (phash)); + memcpy (&phash, peer_id, sizeof (*peer_id)); + h = GNUNET_new (struct GMD_search_handle); + h->peer_id = GNUNET_PEER_intern (peer_id); + h->callback = callback; + h->cls = cls; + h->dhtget = GNUNET_DHT_get_start (dht_handle, /* handle */ + GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */ + &phash, /* key to search */ + dht_replication_level, /* replication level */ + GNUNET_DHT_RO_RECORD_ROUTE | + GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, + NULL, /* xquery */ + 0, /* xquery bits */ + &dht_get_id_handler, h); + GNUNET_CONTAINER_multihashmap32_put (get_requests, h->peer_id, h, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); + return h; +} + +void +GMD_search_stop (struct GMD_search_handle *h) +{ + GNUNET_break (GNUNET_OK == + GNUNET_CONTAINER_multihashmap32_remove (get_requests, + h->peer_id, h)); + GNUNET_DHT_get_stop (h->dhtget); + GNUNET_free (h); +} diff --git a/src/cadet/gnunet-service-cadet_dht.h b/src/cadet/gnunet-service-cadet_dht.h new file mode 100644 index 000000000..6cac531ff --- /dev/null +++ b/src/cadet/gnunet-service-cadet_dht.h @@ -0,0 +1,92 @@ +/* + This file is part of GNUnet. + (C) 2013 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 cadet/gnunet-service-cadet_dht.h + * @brief cadet service; dealing with DHT requests and results + * @author Bartlomiej Polot + * + * All functions in this file should use the prefix GMD (Gnunet Cadet Dht) + */ + +#ifndef GNUNET_SERVICE_CADET_DHT_H +#define GNUNET_SERVICE_CADET_DHT_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "platform.h" +#include "gnunet_util_lib.h" + +struct GMD_search_handle; + + +/** + * Callback called on each path found over the DHT. + * + * @param cls Closure. + * @param path An unchecked, unoptimized path to the target node. + * After callback will no longer be valid! + */ +typedef void (*GMD_search_callback) (void *cls, + const struct CadetPeerPath *path); + +/******************************************************************************/ +/******************************** API ***********************************/ +/******************************************************************************/ + +/** + * Initialize the DHT subsystem. + * + * @param c Configuration. + */ +void +GMD_init (const struct GNUNET_CONFIGURATION_Handle *c); + +/** + * Shut down the DHT subsystem. + */ +void +GMD_shutdown (void); + + +struct GMD_search_handle * +GMD_search (const struct GNUNET_PeerIdentity *peer_id, + GMD_search_callback callback, void *cls); + + +void +GMD_search_stop (struct GMD_search_handle *h); + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_CADET_SERVICE_LOCAL_H */ +#endif +/* end of gnunet-cadet-service_LOCAL.h */ \ No newline at end of file diff --git a/src/cadet/gnunet-service-cadet_hello.c b/src/cadet/gnunet-service-cadet_hello.c new file mode 100644 index 000000000..7eda3f507 --- /dev/null +++ b/src/cadet/gnunet-service-cadet_hello.c @@ -0,0 +1,198 @@ +/* + This file is part of GNUnet. + (C) 2014 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_util_lib.h" + +#include "gnunet_statistics_service.h" +#include "gnunet_peerinfo_service.h" + +#include "cadet_protocol.h" +#include "cadet_path.h" + +#include "gnunet-service-cadet_hello.h" +#include "gnunet-service-cadet_peer.h" + +#define LOG(level, ...) GNUNET_log_from(level,"cadet-hll",__VA_ARGS__) + + +/******************************************************************************/ +/******************************** STRUCTS **********************************/ +/******************************************************************************/ + + + +/******************************************************************************/ +/******************************* GLOBALS ***********************************/ +/******************************************************************************/ + +/** + * Global handle to the statistics service. + */ +extern struct GNUNET_STATISTICS_Handle *stats; + +/** + * Local peer own ID (memory efficient handle). + */ +extern GNUNET_PEER_Id myid; + +/** + * Local peer own ID (full value). + */ +extern struct GNUNET_PeerIdentity my_full_id; + + +/** + * Don't try to recover tunnels if shutting down. + */ +extern int shutting_down; + + +/** + * Hello message of local peer. + */ +const struct GNUNET_HELLO_Message *mine; + +/** + * Handle to peerinfo service. + */ +static struct GNUNET_PEERINFO_Handle *peerinfo; + +/** + * Iterator context. + */ +struct GNUNET_PEERINFO_NotifyContext* nc; + + +/******************************************************************************/ +/******************************** STATIC ***********************************/ +/******************************************************************************/ + +/** + * Process each hello message received from peerinfo. + * + * @param cls Closure (unused). + * @param peer Identity of the peer. + * @param hello Hello of the peer. + * @param err_msg Error message. + */ +static void +got_hello (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_HELLO_Message *hello, + const char *err_msg) +{ + struct CadetPeer *peer; + + if (NULL == id || NULL == hello) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " hello with id %p and msg %p\n", id, hello); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " hello for %s (%d bytes), expires on %s\n", + GNUNET_i2s (id), GNUNET_HELLO_size (hello), + GNUNET_STRINGS_absolute_time_to_string (GNUNET_HELLO_get_last_expiration(hello))); + peer = GMP_get (id); + GMP_set_hello (peer, hello); + + if (GMP_get_short_id (peer) == myid) + { + mine = GMP_get_hello (peer); + LOG (GNUNET_ERROR_TYPE_DEBUG, " updated mine to %p\n", mine); + } +} + + +/******************************************************************************/ +/******************************** API ***********************************/ +/******************************************************************************/ + +/** + * Initialize the hello subsystem. + * + * @param c Configuration. + */ +void +GMH_init (const struct GNUNET_CONFIGURATION_Handle *c) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); + GNUNET_assert (NULL == nc); + peerinfo = GNUNET_PEERINFO_connect (c); + nc = GNUNET_PEERINFO_notify (c, GNUNET_NO, &got_hello, NULL); +} + + +/** + * Shut down the hello subsystem. + */ +void +GMH_shutdown () +{ + if (NULL != nc) + { + GNUNET_PEERINFO_notify_cancel (nc); + nc = NULL; + } + if (NULL != peerinfo) + { + GNUNET_PEERINFO_disconnect (peerinfo); + peerinfo = NULL; + } +} + + +/** + * Get own hello message. + * + * @return Own hello message. + */ +const struct GNUNET_HELLO_Message * +GMH_get_mine (void) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, " mine is %p\n", mine); + return mine; +} + + +/** + * Get another peer's hello message. + * + * @param id ID of the peer whose hello message is requested. + * + * @return Hello message, if any (NULL possible). + */ +const struct GNUNET_HELLO_Message * +GMH_get (const struct GNUNET_PeerIdentity *id) +{ + return GMP_get_hello (GMP_get (id)); +} + + +/** + * Convert a hello message to a string. + * + * @param h Hello message. + */ +char * +GMH_2s (const struct GNUNET_HELLO_Message *h) +{ + return "hello (TODO)"; +} + + diff --git a/src/cadet/gnunet-service-cadet_hello.h b/src/cadet/gnunet-service-cadet_hello.h new file mode 100644 index 000000000..8e978ea9d --- /dev/null +++ b/src/cadet/gnunet-service-cadet_hello.h @@ -0,0 +1,76 @@ +/* + This file is part of GNUnet. + (C) 2014 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 cadet/gnunet-service-cadet_hello.h + * @brief cadet service; dealing with hello messages + * @author Bartlomiej Polot + * + * All functions in this file should use the prefix GMH (Gnunet Cadet Hello) + */ + +#ifndef GNUNET_SERVICE_CADET_HELLO_H +#define GNUNET_SERVICE_CADET_HELLO_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_hello_lib.h" + + +/** + * Initialize the hello subsystem. + * + * @param c Configuration. + */ +void +GMH_init (const struct GNUNET_CONFIGURATION_Handle *c); + +/** + * Shut down the hello subsystem. + */ +void +GMH_shutdown (); + +/** + * Get own hello message. + * + * @return Own hello message. + */ +const struct GNUNET_HELLO_Message * +GMH_get_mine (void); + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_CADET_SERVICE_HELLO_H */ +#endif +/* end of gnunet-cadet-service_hello.h */ diff --git a/src/cadet/gnunet-service-cadet_local.c b/src/cadet/gnunet-service-cadet_local.c new file mode 100644 index 000000000..96596ce68 --- /dev/null +++ b/src/cadet/gnunet-service-cadet_local.c @@ -0,0 +1,1242 @@ +/* + This file is part of GNUnet. + (C) 2013 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_util_lib.h" + +#include "gnunet_statistics_service.h" + +#include "cadet.h" +#include "cadet_protocol.h" /* GNUNET_CADET_Data is shared */ + +#include "gnunet-service-cadet_local.h" +#include "gnunet-service-cadet_channel.h" + +/* INFO DEBUG */ +#include "gnunet-service-cadet_tunnel.h" +#include "gnunet-service-cadet_peer.h" + +#define LOG(level, ...) GNUNET_log_from(level,"cadet-loc",__VA_ARGS__) + +/******************************************************************************/ +/******************************** STRUCTS **********************************/ +/******************************************************************************/ + +/** + * Struct containing information about a client of the service + * + * TODO: add a list of 'waiting' ports + */ +struct CadetClient +{ + /** + * Linked list next + */ + struct CadetClient *next; + + /** + * Linked list prev + */ + struct CadetClient *prev; + + /** + * Tunnels that belong to this client, indexed by local id + */ + struct GNUNET_CONTAINER_MultiHashMap32 *own_channels; + + /** + * Tunnels this client has accepted, indexed by incoming local id + */ + struct GNUNET_CONTAINER_MultiHashMap32 *incoming_channels; + + /** + * Channel ID for the next incoming channel. + */ + CADET_ChannelNumber next_chid; + + /** + * Handle to communicate with the client + */ + struct GNUNET_SERVER_Client *handle; + + /** + * Ports that this client has declared interest in. + * Indexed by port, contains *Client. + */ + struct GNUNET_CONTAINER_MultiHashMap32 *ports; + + /** + * Whether the client is active or shutting down (don't send confirmations + * to a client that is shutting down. + */ + int shutting_down; + + /** + * ID of the client, mainly for debug messages + */ + unsigned int id; +}; + +/******************************************************************************/ +/******************************* GLOBALS ***********************************/ +/******************************************************************************/ + +/** + * Global handle to the statistics service. + */ +extern struct GNUNET_STATISTICS_Handle *stats; + +/** + * Handle to server lib. + */ +static struct GNUNET_SERVER_Handle *server_handle; + +/** + * DLL with all the clients, head. + */ +static struct CadetClient *clients_head; + +/** + * DLL with all the clients, tail. + */ +static struct CadetClient *clients_tail; + +/** + * Next ID to assign to a client. + */ +unsigned int next_client_id; + +/** + * All ports clients of this peer have opened. + */ +static struct GNUNET_CONTAINER_MultiHashMap32 *ports; + +/** + * Notification context, to send messages to local clients. + */ +static struct GNUNET_SERVER_NotificationContext *nc; + + +/******************************************************************************/ +/******************************** STATIC ***********************************/ +/******************************************************************************/ + +/** + * Remove client's ports from the global hashmap on disconnect. + * + * @param cls Closure (unused). + * @param key Port. + * @param value Client structure. + * + * @return GNUNET_OK, keep iterating. + */ +static int +client_release_ports (void *cls, + uint32_t key, + void *value) +{ + int res; + + res = GNUNET_CONTAINER_multihashmap32_remove (ports, key, value); + if (GNUNET_YES != res) + { + GNUNET_break (0); + LOG (GNUNET_ERROR_TYPE_WARNING, + "Port %u by client %p was not registered.\n", + key, value); + } + return GNUNET_OK; +} + + + +/******************************************************************************/ +/******************************** HANDLES ***********************************/ +/******************************************************************************/ + + +/** + * Handler for client connection. + * + * @param cls Closure (unused). + * @param client Client handler. + */ +static void +handle_client_connect (void *cls, struct GNUNET_SERVER_Client *client) +{ + struct CadetClient *c; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "client connected: %p\n", client); + if (NULL == client) + return; + c = GNUNET_new (struct CadetClient); + c->handle = client; + c->id = next_client_id++; /* overflow not important: just for debug */ + c->next_chid = GNUNET_CADET_LOCAL_CHANNEL_ID_SERV; + GNUNET_SERVER_client_keep (client); + GNUNET_SERVER_client_set_user_context (client, c); + GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, c); +} + + +/** + * Iterator for deleting each channel whose client endpoint disconnected. + * + * @param cls Closure (client that has disconnected). + * @param key The local channel id (used to access the hashmap). + * @param value The value stored at the key (channel to destroy). + * + * @return GNUNET_OK, keep iterating. + */ +static int +channel_destroy_iterator (void *cls, + uint32_t key, + void *value) +{ + struct CadetChannel *ch = value; + struct CadetClient *c = cls; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + " Channel %s destroy, due to client %s shutdown.\n", + GMCH_2s (ch), GML_2s (c)); + + GMCH_handle_local_destroy (ch, c, key < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV); + return GNUNET_OK; +} + +/** + * Handler for client disconnection + * + * @param cls closure + * @param client identification of the client; NULL + * for the last call when the server is destroyed + */ +static void +handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) +{ + struct CadetClient *c; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "client disconnected: %p\n", client); + if (client == NULL) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " (SERVER DOWN)\n"); + return; + } + + c = GML_client_get (client); + if (NULL != c) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "matching client found (%u, %p)\n", + c->id, c); + GNUNET_SERVER_client_drop (c->handle); + c->shutting_down = GNUNET_YES; + if (NULL != c->own_channels) + { + GNUNET_CONTAINER_multihashmap32_iterate (c->own_channels, + &channel_destroy_iterator, c); + GNUNET_CONTAINER_multihashmap32_destroy (c->own_channels); + } + + if (NULL != c->incoming_channels) + { + GNUNET_CONTAINER_multihashmap32_iterate (c->incoming_channels, + &channel_destroy_iterator, c); + GNUNET_CONTAINER_multihashmap32_destroy (c->incoming_channels); + } + + if (NULL != c->ports) + { + GNUNET_CONTAINER_multihashmap32_iterate (c->ports, + &client_release_ports, c); + GNUNET_CONTAINER_multihashmap32_destroy (c->ports); + } + GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, c); + GNUNET_STATISTICS_update (stats, "# clients", -1, GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_DEBUG, " client free (%p)\n", c); + GNUNET_free (c); + } + else + { + LOG (GNUNET_ERROR_TYPE_WARNING, " context NULL!\n"); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "done!\n"); + return; +} + + +/** + * Handler for new clients + * + * @param cls closure + * @param client identification of the client + * @param message the actual message, which includes messages the client wants + */ +static void +handle_new_client (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_CADET_ClientConnect *cc_msg; + struct CadetClient *c; + unsigned int size; + uint32_t *p; + unsigned int i; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, "new client connected %p\n", client); + + /* Check data sanity */ + size = ntohs (message->size) - sizeof (struct GNUNET_CADET_ClientConnect); + cc_msg = (struct GNUNET_CADET_ClientConnect *) message; + if (0 != (size % sizeof (uint32_t))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + size /= sizeof (uint32_t); + + /* Initialize new client structure */ + c = GNUNET_SERVER_client_get_user_context (client, struct CadetClient); + LOG (GNUNET_ERROR_TYPE_DEBUG, " client id %u\n", c->id); + LOG (GNUNET_ERROR_TYPE_DEBUG, " client has %u ports\n", size); + if (size > 0) + { + uint32_t u32; + + p = (uint32_t *) &cc_msg[1]; + c->ports = GNUNET_CONTAINER_multihashmap32_create (size); + for (i = 0; i < size; i++) + { + u32 = ntohl (p[i]); + LOG (GNUNET_ERROR_TYPE_DEBUG, " port: %u\n", u32); + + /* store in client's hashmap */ + GNUNET_CONTAINER_multihashmap32_put (c->ports, u32, c, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); + /* store in global hashmap */ + /* FIXME only allow one client to have the port open, + * have a backup hashmap with waiting clients */ + GNUNET_CONTAINER_multihashmap32_put (ports, u32, c, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + } + } + + c->own_channels = GNUNET_CONTAINER_multihashmap32_create (32); + c->incoming_channels = GNUNET_CONTAINER_multihashmap32_create (32); + GNUNET_SERVER_notification_context_add (nc, client); + GNUNET_STATISTICS_update (stats, "# clients", 1, GNUNET_NO); + + GNUNET_SERVER_receive_done (client, GNUNET_OK); + LOG (GNUNET_ERROR_TYPE_DEBUG, "new client processed\n"); +} + + +/** + * Handler for requests of new tunnels + * + * @param cls Closure. + * @param client Identification of the client. + * @param message The actual message. + */ +static void +handle_channel_create (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct CadetClient *c; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, "new channel requested\n"); + + /* Sanity check for client registration */ + if (NULL == (c = GML_client_get (client))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); + + /* Message size sanity check */ + if (sizeof (struct GNUNET_CADET_ChannelMessage) != ntohs (message->size)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + if (GNUNET_OK != + GMCH_handle_local_create (c, + (struct GNUNET_CADET_ChannelMessage *) message)) + { + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; +} + + +/** + * Handler for requests of deleting tunnels + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_channel_destroy (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_CADET_ChannelMessage *msg; + struct CadetClient *c; + struct CadetChannel *ch; + CADET_ChannelNumber chid; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a DESTROY CHANNEL from client!\n"); + + /* Sanity check for client registration */ + if (NULL == (c = GML_client_get (client))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); + + /* Message sanity check */ + if (sizeof (struct GNUNET_CADET_ChannelMessage) != ntohs (message->size)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + msg = (struct GNUNET_CADET_ChannelMessage *) message; + + /* Retrieve tunnel */ + chid = ntohl (msg->channel_id); + LOG (GNUNET_ERROR_TYPE_DEBUG, " for channel %X\n", chid); + ch = GML_channel_get (c, chid); + if (NULL == ch) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " channel %X not found\n", chid); + GNUNET_STATISTICS_update (stats, + "# client destroy messages on unknown channel", + 1, GNUNET_NO); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + GMCH_handle_local_destroy (ch, c, chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV); + + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; +} + + +/** + * Handler for client traffic + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +static void +handle_data (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_CADET_LocalData *msg; + struct CadetClient *c; + struct CadetChannel *ch; + CADET_ChannelNumber chid; + size_t size; + int fwd; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Got data from a client!\n"); + + /* Sanity check for client registration */ + if (NULL == (c = GML_client_get (client))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); + + msg = (struct GNUNET_CADET_LocalData *) message; + + /* Sanity check for message size */ + size = ntohs (message->size) - sizeof (struct GNUNET_CADET_LocalData); + if (size < sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + /* Channel exists? */ + chid = ntohl (msg->id); + LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X\n", chid); + fwd = chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV; + ch = GML_channel_get (c, chid); + if (NULL == ch) + { + GNUNET_STATISTICS_update (stats, + "# client data messages on unknown channel", + 1, GNUNET_NO); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + if (GNUNET_OK != + GMCH_handle_local_data (ch, c, + (struct GNUNET_MessageHeader *)&msg[1], fwd)) + { + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, "receive done OK\n"); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + + return; +} + + +/** + * Handler for client's ACKs for payload traffic. + * + * @param cls Closure (unused). + * @param client Identification of the client. + * @param message The actual message. + */ +static void +handle_ack (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_CADET_LocalAck *msg; + struct CadetChannel *ch; + struct CadetClient *c; + CADET_ChannelNumber chid; + int fwd; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a local ACK\n"); + + /* Sanity check for client registration */ + if (NULL == (c = GML_client_get (client))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); + + msg = (struct GNUNET_CADET_LocalAck *) message; + + /* Channel exists? */ + chid = ntohl (msg->channel_id); + LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X\n", chid); + ch = GML_channel_get (c, chid); + LOG (GNUNET_ERROR_TYPE_DEBUG, " -- ch %p\n", ch); + if (NULL == ch) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %X unknown.\n", chid); + LOG (GNUNET_ERROR_TYPE_DEBUG, " for client %u.\n", c->id); + GNUNET_STATISTICS_update (stats, + "# client ack messages on unknown channel", + 1, GNUNET_NO); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + /* If client is root, the ACK is going FWD, therefore this is "BCK ACK". */ + /* If client is dest, the ACK is going BCK, therefore this is "FWD ACK" */ + fwd = chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV; + + GMCH_handle_local_ack (ch, fwd); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + + return; +} + + + +/** + * Iterator over all peers to send a monitoring client info about each peer. + * + * @param cls Closure (). + * @param peer Peer ID (tunnel remote peer). + * @param value Peer info. + * + * @return #GNUNET_YES, to keep iterating. + */ +static int +get_all_peers_iterator (void *cls, + const struct GNUNET_PeerIdentity * peer, + void *value) +{ + struct GNUNET_SERVER_Client *client = cls; + struct CadetPeer *p = value; + struct GNUNET_CADET_LocalInfoPeer msg; + + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS); + msg.destination = *peer; + msg.paths = htons (GMP_count_paths (p)); + msg.tunnel = htons (NULL != GMP_get_tunnel (p)); + + LOG (GNUNET_ERROR_TYPE_DEBUG, "sending info about peer %s\n", + GNUNET_i2s (peer)); + + GNUNET_SERVER_notification_context_unicast (nc, client, + &msg.header, GNUNET_NO); + return GNUNET_YES; +} + + +/** + * Handler for client's INFO PEERS request. + * + * @param cls Closure (unused). + * @param client Identification of the client. + * @param message The actual message. + */ +static void +handle_get_peers (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct CadetClient *c; + struct GNUNET_MessageHeader reply; + + /* Sanity check for client registration */ + if (NULL == (c = GML_client_get (client))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received get peers request from client %u (%p)\n", + c->id, client); + + GMP_iterate_all (get_all_peers_iterator, client); + reply.size = htons (sizeof (reply)); + reply.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS); + GNUNET_SERVER_notification_context_unicast (nc, client, &reply, GNUNET_NO); + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Get peers request from client %u completed\n", c->id); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Iterator over all tunnels to send a monitoring client info about each tunnel. + * + * @param cls Closure (). + * @param peer Peer ID (tunnel remote peer). + * @param value Tunnel info. + * + * @return #GNUNET_YES, to keep iterating. + */ +static int +get_all_tunnels_iterator (void *cls, + const struct GNUNET_PeerIdentity * peer, + void *value) +{ + struct GNUNET_SERVER_Client *client = cls; + struct CadetTunnel3 *t = value; + struct GNUNET_CADET_LocalInfoTunnel msg; + + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS); + msg.destination = *peer; + msg.channels = htonl (GMT_count_channels (t)); + msg.connections = htonl (GMT_count_connections (t)); + msg.cstate = htons ((uint16_t) GMT_get_cstate (t)); + msg.estate = htons ((uint16_t) GMT_get_estate (t)); + + LOG (GNUNET_ERROR_TYPE_DEBUG, "sending info about tunnel ->%s\n", + GNUNET_i2s (peer)); + + GNUNET_SERVER_notification_context_unicast (nc, client, + &msg.header, GNUNET_NO); + return GNUNET_YES; +} + + +/** + * Handler for client's INFO TUNNELS request. + * + * @param cls Closure (unused). + * @param client Identification of the client. + * @param message The actual message. + */ +static void +handle_get_tunnels (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct CadetClient *c; + struct GNUNET_MessageHeader reply; + + /* Sanity check for client registration */ + if (NULL == (c = GML_client_get (client))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received get tunnels request from client %u (%p)\n", + c->id, client); + + GMT_iterate_all (get_all_tunnels_iterator, client); + reply.size = htons (sizeof (reply)); + reply.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS); + GNUNET_SERVER_notification_context_unicast (nc, client, &reply, GNUNET_NO); + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Get tunnels request from client %u completed\n", c->id); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +static void +iter_connection (void *cls, struct CadetConnection *c) +{ + struct GNUNET_CADET_LocalInfoTunnel *msg = cls; + struct GNUNET_CADET_Hash *h = (struct GNUNET_CADET_Hash *) &msg[1]; + + h[msg->connections] = *(GMC_get_id (c)); + msg->connections++; +} + +static void +iter_channel (void *cls, struct CadetChannel *ch) +{ + struct GNUNET_CADET_LocalInfoTunnel *msg = cls; + struct GNUNET_HashCode *h = (struct GNUNET_HashCode *) &msg[1]; + CADET_ChannelNumber *chn = (CADET_ChannelNumber *) &h[msg->connections]; + + chn[msg->channels] = GMCH_get_id (ch); + msg->channels++; +} + + +/** + * Handler for client's SHOW_TUNNEL request. + * + * @param cls Closure (unused). + * @param client Identification of the client. + * @param message The actual message. + */ +void +handle_show_tunnel (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct GNUNET_CADET_LocalInfo *msg; + struct GNUNET_CADET_LocalInfoTunnel *resp; + struct CadetClient *c; + struct CadetTunnel3 *t; + unsigned int ch_n; + unsigned int c_n; + size_t size; + + /* Sanity check for client registration */ + if (NULL == (c = GML_client_get (client))) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + msg = (struct GNUNET_CADET_LocalInfo *) message; + LOG (GNUNET_ERROR_TYPE_INFO, + "Received tunnel info request from client %u for tunnel %s\n", + c->id, GNUNET_i2s_full(&msg->peer)); + + t = GMP_get_tunnel (GMP_get (&msg->peer)); + if (NULL == t) + { + /* We don't know the tunnel */ + struct GNUNET_CADET_LocalInfoTunnel warn; + + LOG (GNUNET_ERROR_TYPE_INFO, "Tunnel %s unknown %u\n", + GNUNET_i2s_full(&msg->peer), sizeof (warn)); + warn.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL); + warn.header.size = htons (sizeof (warn)); + warn.destination = msg->peer; + warn.channels = htonl (0); + warn.connections = htonl (0); + warn.cstate = htons (0); + warn.estate = htons (0); + + GNUNET_SERVER_notification_context_unicast (nc, client, + &warn.header, + GNUNET_NO); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + /* Initialize context */ + ch_n = GMT_count_channels (t); + c_n = GMT_count_connections (t); + + size = sizeof (struct GNUNET_CADET_LocalInfoTunnel); + size += c_n * sizeof (struct GNUNET_CADET_Hash); + size += ch_n * sizeof (CADET_ChannelNumber); + + resp = GNUNET_malloc (size); + resp->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL); + resp->header.size = htons (size); + GMT_iterate_connections (t, &iter_connection, resp); + GMT_iterate_channels (t, &iter_channel, resp); + /* Do not interleave with iterators, iter_channel needs conn in HBO */ + resp->destination = msg->peer; + resp->connections = htonl (resp->connections); + resp->channels = htonl (resp->channels); + resp->cstate = htons (GMT_get_cstate (t)); + resp->estate = htons (GMT_get_estate (t)); + GNUNET_SERVER_notification_context_unicast (nc, c->handle, + &resp->header, GNUNET_NO); + GNUNET_free (resp); + + LOG (GNUNET_ERROR_TYPE_INFO, + "Show tunnel request from client %u completed. %u conn, %u ch\n", + c->id, c_n, ch_n); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Functions to handle messages from clients + */ +static struct GNUNET_SERVER_MessageHandler client_handlers[] = { + {&handle_new_client, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT, 0}, + {&handle_channel_create, NULL, GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE, + sizeof (struct GNUNET_CADET_ChannelMessage)}, + {&handle_channel_destroy, NULL, GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY, + sizeof (struct GNUNET_CADET_ChannelMessage)}, + {&handle_data, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA, 0}, + {&handle_ack, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK, + sizeof (struct GNUNET_CADET_LocalAck)}, + {&handle_get_peers, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS, + sizeof (struct GNUNET_MessageHeader)}, + {&handle_get_tunnels, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS, + sizeof (struct GNUNET_MessageHeader)}, + {&handle_show_tunnel, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL, + sizeof (struct GNUNET_CADET_LocalInfo)}, + {NULL, NULL, 0, 0} +}; + + + +/******************************************************************************/ +/******************************** API ***********************************/ +/******************************************************************************/ + +/** + * Initialize server subsystem. + * + * @param handle Server handle. + */ +void +GML_init (struct GNUNET_SERVER_Handle *handle) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); + server_handle = handle; + GNUNET_SERVER_suspend (server_handle); + ports = GNUNET_CONTAINER_multihashmap32_create (32); +} + + +/** + * Install server (service) handlers and start listening to clients. + */ +void +GML_start (void) +{ + GNUNET_SERVER_add_handlers (server_handle, client_handlers); + GNUNET_SERVER_connect_notify (server_handle, &handle_client_connect, NULL); + GNUNET_SERVER_disconnect_notify (server_handle, &handle_client_disconnect, + NULL); + nc = GNUNET_SERVER_notification_context_create (server_handle, 1); + + clients_head = NULL; + clients_tail = NULL; + next_client_id = 0; + GNUNET_SERVER_resume (server_handle); +} + + +/** + * Shutdown server. + */ +void +GML_shutdown (void) +{ + if (nc != NULL) + { + GNUNET_SERVER_notification_context_destroy (nc); + nc = NULL; + } +} + + +/** + * Get a channel from a client. + * + * @param c Client to check. + * @param chid Channel ID, must be local (> 0x800...). + * + * @return non-NULL if channel exists in the clients lists + */ +struct CadetChannel * +GML_channel_get (struct CadetClient *c, CADET_ChannelNumber chid) +{ + struct GNUNET_CONTAINER_MultiHashMap32 *map; + + if (0 == (chid & GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)) + { + GNUNET_break_op (0); + LOG (GNUNET_ERROR_TYPE_DEBUG, "CHID %X not a local chid\n", chid); + return NULL; + } + + if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV) + map = c->incoming_channels; + else if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) + map = c->own_channels; + else + { + GNUNET_break (0); + map = NULL; + } + if (NULL == map) + { + GNUNET_break (0); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Client %s does no t have a valid map for CHID %X\n", + GML_2s (c), chid); + return NULL; + } + return GNUNET_CONTAINER_multihashmap32_get (map, chid); +} + + +/** + * Add a channel to a client + * + * @param client Client. + * @param chid Channel ID. + * @param ch Channel. + */ +void +GML_channel_add (struct CadetClient *client, + uint32_t chid, + struct CadetChannel *ch) +{ + if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV) + GNUNET_CONTAINER_multihashmap32_put (client->incoming_channels, chid, ch, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); + else if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) + GNUNET_CONTAINER_multihashmap32_put (client->own_channels, chid, ch, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); + else + GNUNET_break (0); +} + + +/** + * Remove a channel from a client. + * + * @param client Client. + * @param chid Channel ID. + * @param ch Channel. + */ +void +GML_channel_remove (struct CadetClient *client, + uint32_t chid, + struct CadetChannel *ch) +{ + if (GNUNET_CADET_LOCAL_CHANNEL_ID_SERV <= chid) + GNUNET_break (GNUNET_YES == + GNUNET_CONTAINER_multihashmap32_remove (client->incoming_channels, + chid, ch)); + else if (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI <= chid) + GNUNET_break (GNUNET_YES == + GNUNET_CONTAINER_multihashmap32_remove (client->own_channels, + chid, ch)); + else + GNUNET_break (0); +} + + +/** + * Get the tunnel's next free local channel ID. + * + * @param c Client. + * + * @return LID of a channel free to use. + */ +CADET_ChannelNumber +GML_get_next_chid (struct CadetClient *c) +{ + CADET_ChannelNumber chid; + + while (NULL != GML_channel_get (c, c->next_chid)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %u exists...\n", c->next_chid); + c->next_chid = (c->next_chid + 1) | GNUNET_CADET_LOCAL_CHANNEL_ID_SERV; + } + chid = c->next_chid; + c->next_chid = (c->next_chid + 1) | GNUNET_CADET_LOCAL_CHANNEL_ID_SERV; + + return chid; +} + + +/** + * Check if client has registered with the service and has not disconnected + * + * @param client the client to check + * + * @return non-NULL if client exists in the global DLL + */ +struct CadetClient * +GML_client_get (struct GNUNET_SERVER_Client *client) +{ + return GNUNET_SERVER_client_get_user_context (client, struct CadetClient); +} + +/** + * Find a client that has opened a port + * + * @param port Port to check. + * + * @return non-NULL if a client has the port. + */ +struct CadetClient * +GML_client_get_by_port (uint32_t port) +{ + return GNUNET_CONTAINER_multihashmap32_get (ports, port); +} + + +/** + * Deletes a channel from a client (either owner or destination). + * + * @param c Client whose tunnel to delete. + * @param ch Channel which should be deleted. + * @param id Channel ID. + */ +void +GML_client_delete_channel (struct CadetClient *c, + struct CadetChannel *ch, + CADET_ChannelNumber id) +{ + int res; + + if (GNUNET_CADET_LOCAL_CHANNEL_ID_SERV <= id) + { + res = GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels, + id, ch); + if (GNUNET_YES != res) + LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_channel dest KO\n"); + } + else if (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI <= id) + { + res = GNUNET_CONTAINER_multihashmap32_remove (c->own_channels, + id, ch); + if (GNUNET_YES != res) + LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_tunnel root KO\n"); + } + else + { + GNUNET_break (0); + } +} + +/** + * Build a local ACK message and send it to a local client, if needed. + * + * If the client was already allowed to send data, do nothing. + * + * @param c Client to whom send the ACK. + * @param id Channel ID to use + */ +void +GML_send_ack (struct CadetClient *c, CADET_ChannelNumber id) +{ + struct GNUNET_CADET_LocalAck msg; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "send local %s ack on %X towards %p\n", + id < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV ? "FWD" : "BCK", id, c); + + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK); + msg.channel_id = htonl (id); + GNUNET_SERVER_notification_context_unicast (nc, + c->handle, + &msg.header, + GNUNET_NO); + +} + + + +/** + * Notify the client that a new incoming channel was created. + * + * @param c Client to notify. + * @param id Channel ID. + * @param port Channel's destination port. + * @param opt Options (bit array). + * @param peer Origin peer. + */ +void +GML_send_channel_create (struct CadetClient *c, + uint32_t id, uint32_t port, uint32_t opt, + const struct GNUNET_PeerIdentity *peer) +{ + struct GNUNET_CADET_ChannelMessage msg; + + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE); + msg.channel_id = htonl (id); + msg.port = htonl (port); + msg.opt = htonl (opt); + msg.peer = *peer; + GNUNET_SERVER_notification_context_unicast (nc, c->handle, + &msg.header, GNUNET_NO); +} + + +/** + * Build a local channel NACK message and send it to a local client. + * + * @param c Client to whom send the NACK. + * @param id Channel ID to use + */ +void +GML_send_channel_nack (struct CadetClient *c, CADET_ChannelNumber id) +{ + struct GNUNET_CADET_LocalAck msg; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "send local nack on %X towards %p\n", + id, c); + + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK); + msg.channel_id = htonl (id); + GNUNET_SERVER_notification_context_unicast (nc, + c->handle, + &msg.header, + GNUNET_NO); + +} + +/** + * Notify a client that a channel is no longer valid. + * + * @param c Client. + * @param id ID of the channel that is destroyed. + */ +void +GML_send_channel_destroy (struct CadetClient *c, uint32_t id) +{ + struct GNUNET_CADET_ChannelMessage msg; + + if (NULL == c) + { + GNUNET_break (0); + return; + } + if (GNUNET_YES == c->shutting_down) + return; + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY); + msg.channel_id = htonl (id); + msg.port = htonl (0); + memset (&msg.peer, 0, sizeof (msg.peer)); + msg.opt = htonl (0); + GNUNET_SERVER_notification_context_unicast (nc, c->handle, + &msg.header, GNUNET_NO); +} + + +/** + * Modify the cadet message ID from global to local and send to client. + * + * @param c Client to send to. + * @param msg Message to modify and send. + * @param id Channel ID to use (c can be both owner and client). + */ +void +GML_send_data (struct CadetClient *c, + const struct GNUNET_CADET_Data *msg, + CADET_ChannelNumber id) +{ + struct GNUNET_CADET_LocalData *copy; + uint16_t size = ntohs (msg->header.size) - sizeof (struct GNUNET_CADET_Data); + char cbuf[size + sizeof (struct GNUNET_CADET_LocalData)]; + + if (size < sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break_op (0); + return; + } + if (NULL == c) + { + GNUNET_break (0); + return; + } + copy = (struct GNUNET_CADET_LocalData *) cbuf; + memcpy (©[1], &msg[1], size); + copy->header.size = htons (sizeof (struct GNUNET_CADET_LocalData) + size); + copy->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA); + copy->id = htonl (id); + GNUNET_SERVER_notification_context_unicast (nc, c->handle, + ©->header, GNUNET_NO); +} + + +/** + * Get the static string to represent a client. + * + * @param c Client. + * + * @return Static string for the client. + */ +const char * +GML_2s (const struct CadetClient *c) +{ + static char buf[32]; + + sprintf (buf, "%u", c->id); + return buf; +} diff --git a/src/cadet/gnunet-service-cadet_local.h b/src/cadet/gnunet-service-cadet_local.h new file mode 100644 index 000000000..b78b3c5da --- /dev/null +++ b/src/cadet/gnunet-service-cadet_local.h @@ -0,0 +1,226 @@ +/* + This file is part of GNUnet. + (C) 2013 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 cadet/gnunet-service-cadet_local.h + * @brief cadet service; dealing with local clients + * @author Bartlomiej Polot + * + * All functions in this file should use the prefix GML (Gnunet Cadet Local) + */ + +#ifndef GNUNET_SERVICE_CADET_LOCAL_H +#define GNUNET_SERVICE_CADET_LOCAL_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "platform.h" +#include "gnunet_util_lib.h" + +/** + * Struct containing information about a client of the service + */ +struct CadetClient; + +#include "gnunet-service-cadet_channel.h" + +/******************************************************************************/ +/******************************** API ***********************************/ +/******************************************************************************/ + +/** + * Initialize server subsystem. + * + * @param handle Server handle. + */ +void +GML_init (struct GNUNET_SERVER_Handle *handle); + +/** + * Install server (service) handlers and start listening to clients. + */ +void +GML_start (void); + +/** + * Shutdown server. + */ +void +GML_shutdown (void); + +/** + * Get a channel from a client. + * + * @param c Client to check. + * @param chid Channel ID, must be local (> 0x800...). + * + * @return non-NULL if channel exists in the clients lists + */ +struct CadetChannel * +GML_channel_get (struct CadetClient *c, uint32_t chid); + +/** + * Add a channel to a client + * + * @param client Client. + * @param chid Channel ID. + * @param ch Channel. + */ +void +GML_channel_add (struct CadetClient *client, + uint32_t chid, + struct CadetChannel *ch); + +/** + * Remove a channel from a client + * + * @param client Client. + * @param chid Channel ID. + * @param ch Channel. + */ +void +GML_channel_remove (struct CadetClient *client, + uint32_t chid, + struct CadetChannel *ch); + +/** + * Get the tunnel's next free local channel ID. + * + * @param c Client. + * + * @return LID of a channel free to use. + */ +CADET_ChannelNumber +GML_get_next_chid (struct CadetClient *c); + +/** + * Check if client has registered with the service and has not disconnected + * + * @param client the client to check + * + * @return non-NULL if client exists in the global DLL + */ +struct CadetClient * +GML_client_get (struct GNUNET_SERVER_Client *client); + +/** + * Find a client that has opened a port + * + * @param port Port to check. + * + * @return non-NULL if a client has the port. + */ +struct CadetClient * +GML_client_get_by_port (uint32_t port); + +/** + * Deletes a tunnel from a client (either owner or destination). + * + * @param c Client whose tunnel to delete. + * @param ch Channel which should be deleted. + * @param id Channel ID. + */ +void +GML_client_delete_channel (struct CadetClient *c, + struct CadetChannel *ch, + CADET_ChannelNumber id); + +/** + * Build a local ACK message and send it to a local client, if needed. + * + * If the client was already allowed to send data, do nothing. + * + * @param c Client to whom send the ACK. + * @param id Channel ID to use + */ +void +GML_send_ack (struct CadetClient *c, CADET_ChannelNumber id); + +/** + * Notify the appropriate client that a new incoming channel was created. + * + * @param c Client to notify. + * @param id Channel ID. + * @param port Channel's destination port. + * @param opt Options (bit array). + * @param peer Origin peer. + */ +void +GML_send_channel_create (struct CadetClient *c, + uint32_t id, uint32_t port, uint32_t opt, + const struct GNUNET_PeerIdentity *peer); + +/** + * Build a local channel NACK message and send it to a local client. + * + * @param c Client to whom send the NACK. + * @param id Channel ID to use + */ +void +GML_send_channel_nack (struct CadetClient *c, CADET_ChannelNumber id); + +/** + * Notify a client that a channel is no longer valid. + * + * @param c Client. + * @param id ID of the channel that is destroyed. + */ +void +GML_send_channel_destroy (struct CadetClient *c, uint32_t id); + +/** + * Modify the cadet message ID from global to local and send to client. + * + * @param c Client to send to. + * @param msg Message to modify and send. + * @param id Channel ID to use (c can be both owner and client). + */ +void +GML_send_data (struct CadetClient *c, + const struct GNUNET_CADET_Data *msg, + CADET_ChannelNumber id); + +/** + * Get the static string to represent a client. + * + * @param c Client. + * + * @return Static string for the client. + */ +const char * +GML_2s (const struct CadetClient *c); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_CADET_SERVICE_LOCAL_H */ +#endif +/* end of gnunet-cadet-service_LOCAL.h */ diff --git a/src/cadet/gnunet-service-cadet_peer.c b/src/cadet/gnunet-service-cadet_peer.c new file mode 100644 index 000000000..287d42efe --- /dev/null +++ b/src/cadet/gnunet-service-cadet_peer.c @@ -0,0 +1,2219 @@ +/* + This file is part of GNUnet. + (C) 2013 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_util_lib.h" + +#include "gnunet_transport_service.h" +#include "gnunet_core_service.h" +#include "gnunet_statistics_service.h" + +#include "cadet_protocol.h" + +#include "gnunet-service-cadet_peer.h" +#include "gnunet-service-cadet_dht.h" +#include "gnunet-service-cadet_connection.h" +#include "gnunet-service-cadet_tunnel.h" +#include "cadet_path.h" + +#define LOG(level, ...) GNUNET_log_from (level,"cadet-p2p",__VA_ARGS__) + +/******************************************************************************/ +/******************************** STRUCTS **********************************/ +/******************************************************************************/ + +/** + * Struct containing info about a queued transmission to this peer + */ +struct CadetPeerQueue +{ + /** + * DLL next + */ + struct CadetPeerQueue *next; + + /** + * DLL previous + */ + struct CadetPeerQueue *prev; + + /** + * Peer this transmission is directed to. + */ + struct CadetPeer *peer; + + /** + * Connection this message belongs to. + */ + struct CadetConnection *c; + + /** + * Is FWD in c? + */ + int fwd; + + /** + * Pointer to info stucture used as cls. + */ + void *cls; + + /** + * Type of message + */ + uint16_t type; + + /** + * Type of message + */ + uint16_t payload_type; + + /** + * Type of message + */ + uint32_t payload_id; + + /** + * Size of the message + */ + size_t size; + + /** + * Set when this message starts waiting for CORE. + */ + struct GNUNET_TIME_Absolute start_waiting; + + /** + * Function to call on sending. + */ + GMP_sent callback; + + /** + * Closure for callback. + */ + void *callback_cls; +}; + +/** + * Struct containing all information regarding a given peer + */ +struct CadetPeer +{ + /** + * ID of the peer + */ + GNUNET_PEER_Id id; + + /** + * Last time we heard from this peer + */ + struct GNUNET_TIME_Absolute last_contact; + + /** + * Paths to reach the peer, ordered by ascending hop count + */ + struct CadetPeerPath *path_head; + + /** + * Paths to reach the peer, ordered by ascending hop count + */ + struct CadetPeerPath *path_tail; + + /** + * Handle to stop the DHT search for paths to this peer + */ + struct GMD_search_handle *search_h; + + /** + * Tunnel to this peer, if any. + */ + struct CadetTunnel3 *tunnel; + + /** + * Connections that go through this peer, indexed by tid; + */ + struct GNUNET_CONTAINER_MultiHashMap *connections; + + /** + * Handle for queued transmissions + */ + struct GNUNET_CORE_TransmitHandle *core_transmit; + + /** + * Transmission queue to core DLL head + */ + struct CadetPeerQueue *queue_head; + + /** + * Transmission queue to core DLL tail + */ + struct CadetPeerQueue *queue_tail; + + /** + * How many messages are in the queue to this peer. + */ + unsigned int queue_n; + + /** + * Hello message. + */ + struct GNUNET_HELLO_Message* hello; +}; + + +/******************************************************************************/ +/******************************* GLOBALS ***********************************/ +/******************************************************************************/ + +/** + * Global handle to the statistics service. + */ +extern struct GNUNET_STATISTICS_Handle *stats; + +/** + * Local peer own ID (full value). + */ +extern struct GNUNET_PeerIdentity my_full_id; + +/** + * Local peer own ID (short) + */ +extern GNUNET_PEER_Id myid; + +/** + * Peers known, indexed by PeerIdentity (CadetPeer). + */ +static struct GNUNET_CONTAINER_MultiPeerMap *peers; + +/** + * How many peers do we want to remember? + */ +static unsigned long long max_peers; + +/** + * Percentage of messages that will be dropped (for test purposes only). + */ +static unsigned long long drop_percent; + +/** + * Handle to communicate with core. + */ +static struct GNUNET_CORE_Handle *core_handle; + +/** + * Handle to try to start new connections. + */ +static struct GNUNET_TRANSPORT_Handle *transport_handle; + + +/******************************************************************************/ +/***************************** DEBUG *********************************/ +/******************************************************************************/ + +static void +queue_debug (struct CadetPeer *peer) +{ + struct CadetPeerQueue *q; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "QQQ Messages queued towards %s\n", GMP_2s (peer)); + LOG (GNUNET_ERROR_TYPE_DEBUG, "QQQ core tmt rdy: %p\n", peer->core_transmit); + + for (q = peer->queue_head; NULL != q; q = q->next) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "QQQ - %s %s on %s\n", + GM_m2s (q->type), GM_f2s (q->fwd), GMC_2s (q->c)); + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, "QQQ End queued towards %s\n", GMP_2s (peer)); +} + + +/******************************************************************************/ +/***************************** CORE HELPERS *********************************/ +/******************************************************************************/ + + +/** + * Iterator to notify all connections of a broken link. Mark connections + * to destroy after all traffic has been sent. + * + * @param cls Closure (peer disconnected). + * @param key Current key code (peer id). + * @param value Value in the hash map (connection). + * + * @return #GNUNET_YES to continue to iterate. + */ +static int +notify_broken (void *cls, + const struct GNUNET_HashCode *key, + void *value) +{ + struct CadetPeer *peer = cls; + struct CadetConnection *c = value; + + LOG (GNUNET_ERROR_TYPE_DEBUG, " notifying %s due to %s\n", + GMC_2s (c), GMP_2s (peer)); + GMC_notify_broken (c, peer); + + return GNUNET_YES; +} + + +/** + * Remove the direct path to the peer. + * + * @param peer Peer to remove the direct path from. + * + */ +static struct CadetPeerPath * +pop_direct_path (struct CadetPeer *peer) +{ + struct CadetPeerPath *iter; + + for (iter = peer->path_head; NULL != iter; iter = iter->next) + { + if (2 <= iter->length) + { + GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, iter); + return iter; + } + } + return NULL; +} + + +/******************************************************************************/ +/***************************** CORE CALLBACKS *********************************/ +/******************************************************************************/ + +/** + * Method called whenever a given peer connects. + * + * @param cls closure + * @param peer peer identity this notification is about + */ +static void +core_connect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct CadetPeer *mp; + struct CadetPeerPath *path; + char own_id[16]; + + strncpy (own_id, GNUNET_i2s (&my_full_id), 15); + mp = GMP_get (peer); + if (myid == mp->id) + { + LOG (GNUNET_ERROR_TYPE_INFO, "CONNECTED %s (self)\n", own_id); + path = path_new (1); + } + else + { + LOG (GNUNET_ERROR_TYPE_INFO, "CONNECTED %s <= %s\n", + own_id, GNUNET_i2s (peer)); + path = path_new (2); + path->peers[1] = mp->id; + GNUNET_PEER_change_rc (mp->id, 1); + GNUNET_STATISTICS_update (stats, "# peers", 1, GNUNET_NO); + } + path->peers[0] = myid; + GNUNET_PEER_change_rc (myid, 1); + GMP_add_path (mp, path, GNUNET_YES); + + mp->connections = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_YES); + + if (NULL != GMP_get_tunnel (mp) && + 0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, peer)) + { + GMP_connect (mp); + } + + return; +} + + +/** + * Method called whenever a peer disconnects. + * + * @param cls closure + * @param peer peer identity this notification is about + */ +static void +core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +{ + struct CadetPeer *p; + struct CadetPeerPath *direct_path; + char own_id[16]; + + strncpy (own_id, GNUNET_i2s (&my_full_id), 15); + p = GNUNET_CONTAINER_multipeermap_get (peers, peer); + if (NULL == p) + { + GNUNET_break (0); + return; + } + if (myid == p->id) + LOG (GNUNET_ERROR_TYPE_INFO, "DISCONNECTED %s (self)\n", own_id); + else + LOG (GNUNET_ERROR_TYPE_DEBUG, "DISCONNECTED %s <= %s\n", + own_id, GNUNET_i2s (peer)); + direct_path = pop_direct_path (p); + GNUNET_CONTAINER_multihashmap_iterate (p->connections, ¬ify_broken, p); + GNUNET_CONTAINER_multihashmap_destroy (p->connections); + p->connections = NULL; + if (NULL != p->core_transmit) + { + GNUNET_CORE_notify_transmit_ready_cancel (p->core_transmit); + p->core_transmit = NULL; + } + GNUNET_STATISTICS_update (stats, "# peers", -1, GNUNET_NO); + + path_destroy (direct_path); + return; +} + + +/** + * Functions to handle messages from core + */ +static struct GNUNET_CORE_MessageHandler core_handlers[] = { + {&GMC_handle_create, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, 0}, + {&GMC_handle_confirm, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK, + sizeof (struct GNUNET_CADET_ConnectionACK)}, + {&GMC_handle_broken, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN, + sizeof (struct GNUNET_CADET_ConnectionBroken)}, + {&GMC_handle_destroy, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY, + sizeof (struct GNUNET_CADET_ConnectionDestroy)}, + {&GMC_handle_ack, GNUNET_MESSAGE_TYPE_CADET_ACK, + sizeof (struct GNUNET_CADET_ACK)}, + {&GMC_handle_poll, GNUNET_MESSAGE_TYPE_CADET_POLL, + sizeof (struct GNUNET_CADET_Poll)}, + {&GMC_handle_encrypted, GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED, 0}, + {&GMC_handle_kx, GNUNET_MESSAGE_TYPE_CADET_KX, 0}, + {NULL, 0, 0} +}; + + +/** + * To be called on core init/fail. + * + * @param cls Closure (config) + * @param identity the public identity of this peer + */ +static void +core_init (void *cls, + const struct GNUNET_PeerIdentity *identity) +{ + const struct GNUNET_CONFIGURATION_Handle *c = cls; + static int i = 0; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Core init\n"); + if (0 != memcmp (identity, &my_full_id, sizeof (my_full_id))) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong CORE service\n")); + LOG (GNUNET_ERROR_TYPE_ERROR, " core id %s\n", GNUNET_i2s (identity)); + LOG (GNUNET_ERROR_TYPE_ERROR, " my id %s\n", GNUNET_i2s (&my_full_id)); + GNUNET_CORE_disconnect (core_handle); + core_handle = GNUNET_CORE_connect (c, /* Main configuration */ + NULL, /* Closure passed to CADET functions */ + &core_init, /* Call core_init once connected */ + &core_connect, /* Handle connects */ + &core_disconnect, /* remove peers on disconnects */ + NULL, /* Don't notify about all incoming messages */ + GNUNET_NO, /* For header only in notification */ + NULL, /* Don't notify about all outbound messages */ + GNUNET_NO, /* For header-only out notification */ + core_handlers); /* Register these handlers */ + if (10 < i++) + GNUNET_abort(); + } + GML_start (); + return; +} + + +/** + * Core callback to write a pre-constructed data packet to core buffer + * + * @param cls Closure (CadetTransmissionDescriptor with data in "data" member). + * @param size Number of bytes available in buf. + * @param buf Where the to write the message. + * + * @return number of bytes written to buf + */ +static size_t +send_core_data_raw (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader *msg = cls; + size_t total_size; + + GNUNET_assert (NULL != msg); + total_size = ntohs (msg->size); + + if (total_size > size) + { + GNUNET_break (0); + return 0; + } + memcpy (buf, msg, total_size); + GNUNET_free (cls); + return total_size; +} + + +/** + * Function to send a create connection message to a peer. + * + * @param c Connection to create. + * @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 +send_core_connection_create (struct CadetConnection *c, size_t size, void *buf) +{ + struct GNUNET_CADET_ConnectionCreate *msg; + struct GNUNET_PeerIdentity *peer_ptr; + const struct CadetPeerPath *p = GMC_get_path (c); + size_t size_needed; + int i; + + if (NULL == p) + return 0; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending CONNECTION CREATE...\n"); + size_needed = + sizeof (struct GNUNET_CADET_ConnectionCreate) + + p->length * sizeof (struct GNUNET_PeerIdentity); + + if (size < size_needed || NULL == buf) + { + GNUNET_break (0); + return 0; + } + msg = (struct GNUNET_CADET_ConnectionCreate *) buf; + msg->header.size = htons (size_needed); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE); + msg->cid = *GMC_get_id (c); + + peer_ptr = (struct GNUNET_PeerIdentity *) &msg[1]; + for (i = 0; i < p->length; i++) + { + GNUNET_PEER_resolve (p->peers[i], peer_ptr++); + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "CONNECTION CREATE (%u bytes long) sent!\n", + size_needed); + return size_needed; +} + + +/** + * Creates a path ack message in buf and frees all unused resources. + * + * @param c Connection to send an ACK on. + * @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 +send_core_connection_ack (struct CadetConnection *c, size_t size, void *buf) +{ + struct GNUNET_CADET_ConnectionACK *msg = buf; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending CONNECTION ACK...\n"); + if (sizeof (struct GNUNET_CADET_ConnectionACK) > size) + { + GNUNET_break (0); + return 0; + } + msg->header.size = htons (sizeof (struct GNUNET_CADET_ConnectionACK)); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK); + msg->cid = *GMC_get_id (c); + + LOG (GNUNET_ERROR_TYPE_DEBUG, "CONNECTION ACK sent!\n"); + return sizeof (struct GNUNET_CADET_ConnectionACK); +} + + +/******************************************************************************/ +/******************************** STATIC ***********************************/ +/******************************************************************************/ + + +/** + * Get priority for a queued message. + * + * @param q Queued message + * + * @return CORE priority to use. + */ +static enum GNUNET_CORE_Priority +get_priority (struct CadetPeerQueue *q) +{ + enum GNUNET_CORE_Priority low; + enum GNUNET_CORE_Priority high; + + if (NULL == q) + { + GNUNET_break (0); + return GNUNET_CORE_PRIO_BACKGROUND; + } + + /* Relayed traffic has lower priority, our own traffic has higher */ + if (NULL == q->c || GNUNET_NO == GMC_is_origin (q->c, q->fwd)) + { + low = GNUNET_CORE_PRIO_BEST_EFFORT; + high = GNUNET_CORE_PRIO_URGENT; + } + else + { + low = GNUNET_CORE_PRIO_URGENT; + high = GNUNET_CORE_PRIO_CRITICAL_CONTROL; + } + + /* Bulky payload has lower priority, control traffic has higher. */ + if (GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED == q->type) + return low; + else + return high; +} + + +/** + * Iterator over tunnel hash map entries to destroy the tunnel during shutdown. + * + * @param cls closure + * @param key current key code + * @param value value in the hash map + * @return #GNUNET_YES if we should continue to iterate, + * #GNUNET_NO if not. + */ +static int +shutdown_tunnel (void *cls, + const struct GNUNET_PeerIdentity *key, + void *value) +{ + struct CadetPeer *p = value; + struct CadetTunnel3 *t = p->tunnel; + + if (NULL != t) + GMT_destroy (t); + return GNUNET_YES; +} + + +/** + * Destroy the peer_info and free any allocated resources linked to it + * + * @param peer The peer_info to destroy. + * + * @return GNUNET_OK on success + */ +static int +peer_destroy (struct CadetPeer *peer) +{ + struct GNUNET_PeerIdentity id; + struct CadetPeerPath *p; + struct CadetPeerPath *nextp; + + GNUNET_PEER_resolve (peer->id, &id); + GNUNET_PEER_change_rc (peer->id, -1); + + LOG (GNUNET_ERROR_TYPE_WARNING, "destroying peer %s\n", GNUNET_i2s (&id)); + + if (GNUNET_YES != + GNUNET_CONTAINER_multipeermap_remove (peers, &id, peer)) + { + GNUNET_break (0); + LOG (GNUNET_ERROR_TYPE_WARNING, " not in peermap!!\n"); + } + if (NULL != peer->search_h) + { + GMD_search_stop (peer->search_h); + } + p = peer->path_head; + while (NULL != p) + { + nextp = p->next; + GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, p); + path_destroy (p); + p = nextp; + } + GMT_destroy_empty (peer->tunnel); + GNUNET_free (peer); + return GNUNET_OK; +} + + +/** + * Returns if peer is used (has a tunnel or is neighbor). + * + * @param peer Peer to check. + * + * @return #GNUNET_YES if peer is in use. + */ +static int +peer_is_used (struct CadetPeer *peer) +{ + struct CadetPeerPath *p; + + if (NULL != peer->tunnel) + return GNUNET_YES; + + for (p = peer->path_head; NULL != p; p = p->next) + { + if (p->length < 3) + return GNUNET_YES; + } + return GNUNET_NO; +} + + +/** + * Iterator over all the peers to get the oldest timestamp. + * + * @param cls Closure (unsued). + * @param key ID of the peer. + * @param value Peer_Info of the peer. + */ +static int +peer_get_oldest (void *cls, + const struct GNUNET_PeerIdentity *key, + void *value) +{ + struct CadetPeer *p = value; + struct GNUNET_TIME_Absolute *abs = cls; + + /* Don't count active peers */ + if (GNUNET_YES == peer_is_used (p)) + return GNUNET_YES; + + if (abs->abs_value_us < p->last_contact.abs_value_us) + abs->abs_value_us = p->last_contact.abs_value_us; + + return GNUNET_YES; +} + + +/** + * Iterator over all the peers to remove the oldest entry. + * + * @param cls Closure (unsued). + * @param key ID of the peer. + * @param value Peer_Info of the peer. + */ +static int +peer_timeout (void *cls, + const struct GNUNET_PeerIdentity *key, + void *value) +{ + struct CadetPeer *p = value; + struct GNUNET_TIME_Absolute *abs = cls; + + LOG (GNUNET_ERROR_TYPE_WARNING, + "peer %s timeout\n", GNUNET_i2s (key)); + + if (p->last_contact.abs_value_us == abs->abs_value_us && + GNUNET_NO == peer_is_used (p)) + { + peer_destroy (p); + return GNUNET_NO; + } + return GNUNET_YES; +} + + +/** + * Delete oldest unused peer. + */ +static void +peer_delete_oldest (void) +{ + struct GNUNET_TIME_Absolute abs; + + abs = GNUNET_TIME_UNIT_FOREVER_ABS; + + GNUNET_CONTAINER_multipeermap_iterate (peers, + &peer_get_oldest, + &abs); + GNUNET_CONTAINER_multipeermap_iterate (peers, + &peer_timeout, + &abs); +} + + +/** + * Choose the best (yet unused) path towards a peer, + * considering the tunnel properties. + * + * @param peer The destination peer. + * + * @return Best current known path towards the peer, if any. + */ +static struct CadetPeerPath * +peer_get_best_path (const struct CadetPeer *peer) +{ + struct CadetPeerPath *best_p; + struct CadetPeerPath *p; + unsigned int best_cost; + unsigned int cost; + + best_cost = UINT_MAX; + best_p = NULL; + for (p = peer->path_head; NULL != p; p = p->next) + { + if (GNUNET_NO == path_is_valid (p)) + continue; /* Don't use invalid paths. */ + if (GNUNET_YES == GMT_is_path_used (peer->tunnel, p)) + continue; /* If path is already in use, skip it. */ + + if ((cost = GMT_get_path_cost (peer->tunnel, p)) < best_cost) + { + best_cost = cost; + best_p = p; + } + } + return best_p; +} + + +/** + * Is this queue element sendable? + * + * - All management traffic is always sendable. + * - For payload traffic, check the connection flow control. + * + * @param q Queue element to inspect. + * + * @return #GNUNET_YES if it is sendable, #GNUNET_NO otherwise. + */ +static int +queue_is_sendable (struct CadetPeerQueue *q) +{ + /* Is PID-independent? */ + switch (q->type) + { + case GNUNET_MESSAGE_TYPE_CADET_ACK: + case GNUNET_MESSAGE_TYPE_CADET_POLL: + case GNUNET_MESSAGE_TYPE_CADET_KX: + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE: + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK: + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY: + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN: + return GNUNET_YES; + + case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED: + break; + + default: + GNUNET_break (0); + } + + return GMC_is_sendable (q->c, q->fwd); +} + + +/** + * Get first sendable message. + * + * @param peer The destination peer. + * + * @return First transmittable message, if any. Otherwise, NULL. + */ +static struct CadetPeerQueue * +peer_get_first_message (const struct CadetPeer *peer) +{ + struct CadetPeerQueue *q; + + for (q = peer->queue_head; NULL != q; q = q->next) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking %p towards %s\n", q, GMC_2s (q->c)); + if (queue_is_sendable (q)) + return q; + } + + return NULL; +} + + +/** + * Function to process paths received for a new peer addition. The recorded + * paths form the initial tunnel, which can be optimized later. + * Called on each result obtained for the DHT search. + * + * @param cls closure + * @param path + */ +static void +search_handler (void *cls, const struct CadetPeerPath *path) +{ + struct CadetPeer *peer = cls; + unsigned int connection_count; + + GMP_add_path_to_all (path, GNUNET_NO); + + /* Count connections */ + connection_count = GMT_count_connections (peer->tunnel); + + /* If we already have 3 (or more (?!)) connections, it's enough */ + if (3 <= connection_count) + return; + + if (CADET_TUNNEL3_SEARCHING == GMT_get_cstate (peer->tunnel)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " ... connect!\n"); + GMP_connect (peer); + } + return; +} + + + +/** + * Core callback to write a queued packet to core buffer + * + * @param cls Closure (peer info). + * @param size Number of bytes available in buf. + * @param buf Where the to write the message. + * + * @return number of bytes written to buf + */ +static size_t +queue_send (void *cls, size_t size, void *buf) +{ + struct CadetPeer *peer = cls; + struct CadetConnection *c; + struct CadetPeerQueue *queue; + const struct GNUNET_PeerIdentity *dst_id; + size_t data_size; + uint32_t pid; + + pid = 0; + peer->core_transmit = NULL; + LOG (GNUNET_ERROR_TYPE_DEBUG, "Queue send towards %s (max %u)\n", + GMP_2s (peer), size); + + if (NULL == buf || 0 == size) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Buffer size 0.\n"); + return 0; + } + + /* Initialize */ + queue = peer_get_first_message (peer); + if (NULL == queue) + { + GNUNET_assert (0); /* Core tmt_rdy should've been canceled */ + return 0; + } + c = queue->c; + + dst_id = GNUNET_PEER_resolve2 (peer->id); + LOG (GNUNET_ERROR_TYPE_DEBUG, " on connection %s %s\n", + GMC_2s (c), GM_f2s(queue->fwd)); + /* Check if buffer size is enough for the message */ + if (queue->size > size) + { + LOG (GNUNET_ERROR_TYPE_WARNING, "not enough room (%u vs %u), reissue\n", + queue->size, size); + peer->core_transmit = + GNUNET_CORE_notify_transmit_ready (core_handle, + GNUNET_NO, get_priority (queue), + GNUNET_TIME_UNIT_FOREVER_REL, + dst_id, + queue->size, + &queue_send, + peer); + return 0; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " size %u ok\n", queue->size); + + /* Fill buf */ + switch (queue->type) + { + case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED: + pid = GMC_get_pid (queue->c, queue->fwd); + LOG (GNUNET_ERROR_TYPE_DEBUG, " payload ID %u\n", pid); + data_size = send_core_data_raw (queue->cls, size, buf); + ((struct GNUNET_CADET_Encrypted *) buf)->pid = htonl (pid); + break; + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY: + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN: + case GNUNET_MESSAGE_TYPE_CADET_KX: + case GNUNET_MESSAGE_TYPE_CADET_ACK: + case GNUNET_MESSAGE_TYPE_CADET_POLL: + LOG (GNUNET_ERROR_TYPE_DEBUG, " raw %s\n", GM_m2s (queue->type)); + data_size = send_core_data_raw (queue->cls, size, buf); + break; + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE: + LOG (GNUNET_ERROR_TYPE_DEBUG, " path create\n"); + if (GMC_is_origin (c, GNUNET_YES)) + data_size = send_core_connection_create (queue->c, size, buf); + else + data_size = send_core_data_raw (queue->cls, size, buf); + break; + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK: + LOG (GNUNET_ERROR_TYPE_DEBUG, " path ack\n"); + if (GMC_is_origin (c, GNUNET_NO) || + GMC_is_origin (c, GNUNET_YES)) + data_size = send_core_connection_ack (queue->c, size, buf); + else + data_size = send_core_data_raw (queue->cls, size, buf); + break; + case GNUNET_MESSAGE_TYPE_CADET_DATA: + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE: + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: + /* This should be encapsulted */ + GNUNET_break (0); + data_size = 0; + break; + default: + GNUNET_break (0); + LOG (GNUNET_ERROR_TYPE_WARNING, " type unknown: %u\n", queue->type); + data_size = 0; + } + + if (0 < drop_percent && + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 101) < drop_percent) + { + LOG (GNUNET_ERROR_TYPE_WARNING, "DD %s on connection %s\n", + GM_m2s (queue->type), GMC_2s (c)); + data_size = 0; + } + else + { + LOG (GNUNET_ERROR_TYPE_INFO, + "snd %s (%s %u) on connection %s (%p) %s (size %u)\n", + GM_m2s (queue->type), GM_m2s (queue->payload_type), + queue->payload_type, GMC_2s (c), c, GM_f2s (queue->fwd), data_size); + } + + /* Free queue, but cls was freed by send_core_* */ + GMP_queue_destroy (queue, GNUNET_NO, GNUNET_YES, pid); + + /* If more data in queue, send next */ + queue = peer_get_first_message (peer); + if (NULL != queue) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " more data!\n"); + if (NULL == peer->core_transmit) + { + peer->core_transmit = + GNUNET_CORE_notify_transmit_ready (core_handle, + GNUNET_NO, get_priority (queue), + GNUNET_TIME_UNIT_FOREVER_REL, + dst_id, + queue->size, + &queue_send, + peer); + queue->start_waiting = GNUNET_TIME_absolute_get (); + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "* tmt rdy called somewhere else\n"); + } +// GMC_start_poll (); FIXME needed? + } + else + { +// GMC_stop_poll(); FIXME needed? + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, " return %d\n", data_size); + queue_debug (peer); + return data_size; +} + + +/******************************************************************************/ +/******************************** API ***********************************/ +/******************************************************************************/ + + +/** + * Free a transmission that was already queued with all resources + * associated to the request. + * + * @param queue Queue handler to cancel. + * @param clear_cls Is it necessary to free associated cls? + * @param sent Was it really sent? (Could have been canceled) + * @param pid PID, if relevant (was sent and was a payload message). + */ +void +GMP_queue_destroy (struct CadetPeerQueue *queue, int clear_cls, + int sent, uint32_t pid) +{ + struct CadetPeer *peer; + + peer = queue->peer; + + if (GNUNET_YES == clear_cls) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "queue destroy type %s\n", + GM_m2s (queue->type)); + switch (queue->type) + { + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY: + LOG (GNUNET_ERROR_TYPE_INFO, "destroying a DESTROY message\n"); + /* fall through */ + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK: + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE: + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN: + case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE: + case GNUNET_MESSAGE_TYPE_CADET_KX: + case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED: + case GNUNET_MESSAGE_TYPE_CADET_ACK: + case GNUNET_MESSAGE_TYPE_CADET_POLL: + GNUNET_free_non_null (queue->cls); + break; + + default: + GNUNET_break (0); + LOG (GNUNET_ERROR_TYPE_ERROR, " type %s unknown!\n", + GM_m2s (queue->type)); + } + } + GNUNET_CONTAINER_DLL_remove (peer->queue_head, peer->queue_tail, queue); + + if (queue->type != GNUNET_MESSAGE_TYPE_CADET_ACK && + queue->type != GNUNET_MESSAGE_TYPE_CADET_POLL) + { + peer->queue_n--; + } + + if (NULL != queue->callback) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " calling callback\n"); + queue->callback (queue->callback_cls, + queue->c, sent, queue->type, pid, + queue->fwd, queue->size, + GNUNET_TIME_absolute_get_duration (queue->start_waiting)); + } + + if (NULL == peer_get_first_message (peer) && NULL != peer->core_transmit) + { + GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit); + peer->core_transmit = NULL; + } + + GNUNET_free (queue); +} + + +/** + * @brief Queue and pass message to core when possible. + * + * @param peer Peer towards which to queue the message. + * @param cls Closure (@c type dependant). It will be used by queue_send to + * build the message to be sent if not already prebuilt. + * @param type Type of the message, 0 for a raw message. + * @param size Size of the message. + * @param c Connection this message belongs to (can be NULL). + * @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!) + * @param cont Continuation to be called once CORE has taken the message. + * @param cont_cls Closure for @c cont. + * + * @return Handle to cancel the message before it is sent. Once cont is called + * message has been sent and therefore the handle is no longer valid. + */ +struct CadetPeerQueue * +GMP_queue_add (struct CadetPeer *peer, void *cls, uint16_t type, + uint16_t payload_type, uint32_t payload_id, size_t size, + struct CadetConnection *c, int fwd, + GMP_sent cont, void *cont_cls) +{ + struct CadetPeerQueue *queue; + int priority; + int call_core; + + LOG (GNUNET_ERROR_TYPE_INFO, + "que %s (%s %u) on connection %s (%p) %s towards %s (size %u)\n", + GM_m2s (type), GM_m2s (payload_type), payload_id, + GMC_2s (c), c, GM_f2s (fwd), GMP_2s (peer), size); + + if (NULL == peer->connections) + { + /* We are not connected to this peer, ignore request. */ + LOG (GNUNET_ERROR_TYPE_WARNING, "%s not a neighbor\n", GMP_2s (peer)); + GNUNET_STATISTICS_update (stats, "# messages dropped due to wrong hop", 1, + GNUNET_NO); + return NULL; + } + + priority = 0; + + if (GNUNET_MESSAGE_TYPE_CADET_POLL == type || + GNUNET_MESSAGE_TYPE_CADET_ACK == type) + { + priority = 100; + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, "priority %d\n", priority); + + call_core = NULL == c ? GNUNET_YES : GMC_is_sendable (c, fwd); + queue = GNUNET_new (struct CadetPeerQueue); + queue->cls = cls; + queue->type = type; + queue->payload_type = payload_type; + queue->payload_id = payload_id; + queue->size = size; + queue->peer = peer; + queue->c = c; + queue->fwd = fwd; + queue->callback = cont; + queue->callback_cls = cont_cls; + if (100 > priority) + { + GNUNET_CONTAINER_DLL_insert_tail (peer->queue_head, peer->queue_tail, queue); + peer->queue_n++; + } + else + { + GNUNET_CONTAINER_DLL_insert (peer->queue_head, peer->queue_tail, queue); + call_core = GNUNET_YES; + } + + if (NULL == peer->core_transmit && GNUNET_YES == call_core) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "calling core tmt rdy towards %s for %u bytes\n", + GMP_2s (peer), size); + peer->core_transmit = + GNUNET_CORE_notify_transmit_ready (core_handle, + GNUNET_NO, get_priority (queue), + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_PEER_resolve2 (peer->id), + size, + &queue_send, + peer); + queue->start_waiting = GNUNET_TIME_absolute_get (); + } + else if (GNUNET_NO == call_core) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "core tmt rdy towards %s not needed\n", + GMP_2s (peer)); + + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "core tmt rdy towards %s already called\n", + GMP_2s (peer)); + + } + queue_debug (peer); + return queue; +} + + +/** + * Cancel all queued messages to a peer that belong to a certain connection. + * + * @param peer Peer towards whom to cancel. + * @param c Connection whose queued messages to cancel. Might be destroyed by + * the sent continuation call. + */ +void +GMP_queue_cancel (struct CadetPeer *peer, struct CadetConnection *c) +{ + struct CadetPeerQueue *q; + struct CadetPeerQueue *next; + struct CadetPeerQueue *prev; + + for (q = peer->queue_head; NULL != q; q = next) + { + prev = q->prev; + if (q->c == c) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "GMP queue cancel %s\n", GM_m2s (q->type)); + if (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY != q->type) + { + q->c = NULL; + } + else + { + GMP_queue_destroy (q, GNUNET_YES, GNUNET_NO, 0); + } + + /* Get next from prev, q->next might be already freed: + * queue destroy -> callback -> GMC_destroy -> cancel_queues -> here + */ + if (NULL == prev) + next = peer->queue_head; + else + next = prev->next; + } + else + { + next = q->next; + } + } + if (NULL == peer->queue_head) + { + if (NULL != peer->core_transmit) + { + GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit); + peer->core_transmit = NULL; + } + } +} + + +/** + * Get the first transmittable message for a connection. + * + * @param peer Neighboring peer. + * @param c Connection. + * + * @return First transmittable message. + */ +static struct CadetPeerQueue * +connection_get_first_message (struct CadetPeer *peer, struct CadetConnection *c) +{ + struct CadetPeerQueue *q; + + for (q = peer->queue_head; NULL != q; q = q->next) + { + if (q->c != c) + continue; + if (queue_is_sendable (q)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " sendable!!\n"); + return q; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " not sendable\n"); + } + + return NULL; +} + + +/** + * Get the first message for a connection and unqueue it. + * + * @param peer Neighboring peer. + * @param c Connection. + * + * @return First message for this connection. + */ +struct GNUNET_MessageHeader * +GMP_connection_pop (struct CadetPeer *peer, struct CadetConnection *c) +{ + struct CadetPeerQueue *q; + struct CadetPeerQueue *next; + struct GNUNET_MessageHeader *msg; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection pop on %s\n", GMC_2s (c)); + for (q = peer->queue_head; NULL != q; q = next) + { + next = q->next; + if (q->c != c) + continue; + switch (q->type) + { + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE: + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK: + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY: + case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN: + case GNUNET_MESSAGE_TYPE_CADET_ACK: + case GNUNET_MESSAGE_TYPE_CADET_POLL: + GMP_queue_destroy (q, GNUNET_YES, GNUNET_NO, 0); + continue; + + case GNUNET_MESSAGE_TYPE_CADET_KX: + case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED: + msg = (struct GNUNET_MessageHeader *) q->cls; + GMP_queue_destroy (q, GNUNET_NO, GNUNET_NO, 0); + return msg; + + default: + GNUNET_break (0); + } + } + + return NULL; +} + + +void +GMP_queue_unlock (struct CadetPeer *peer, struct CadetConnection *c) +{ + struct CadetPeerQueue *q; + size_t size; + + if (NULL != peer->core_transmit) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " already unlocked!\n"); + return; /* Already unlocked */ + } + + q = connection_get_first_message (peer, c); + if (NULL == q) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " queue empty!\n"); + return; /* Nothing to transmit */ + } + + size = q->size; + peer->core_transmit = + GNUNET_CORE_notify_transmit_ready (core_handle, + GNUNET_NO, get_priority (q), + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_PEER_resolve2 (peer->id), + size, + &queue_send, + peer); +} + + +/** + * Initialize the peer subsystem. + * + * @param c Configuration. + */ +void +GMP_init (const struct GNUNET_CONFIGURATION_Handle *c) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); + peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_PEERS", + &max_peers)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, + "CADET", "MAX_PEERS", "USING DEFAULT"); + max_peers = 1000; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (c, "CADET", "DROP_PERCENT", + &drop_percent)) + { + drop_percent = 0; + } + else + { + LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n"); + LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n"); + LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n"); + LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n"); + LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n"); + } + + core_handle = GNUNET_CORE_connect (c, /* Main configuration */ + NULL, /* Closure passed to CADET functions */ + &core_init, /* Call core_init once connected */ + &core_connect, /* Handle connects */ + &core_disconnect, /* remove peers on disconnects */ + NULL, /* Don't notify about all incoming messages */ + GNUNET_NO, /* For header only in notification */ + NULL, /* Don't notify about all outbound messages */ + GNUNET_NO, /* For header-only out notification */ + core_handlers); /* Register these handlers */ + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_yesno (c, "CADET", "DISABLE_TRY_CONNECT")) + { + transport_handle = GNUNET_TRANSPORT_connect (c, &my_full_id, NULL, /* cls */ + /* Notify callbacks */ + NULL, NULL, NULL); + } + else + { + LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n"); + LOG (GNUNET_ERROR_TYPE_WARNING, "* DISABLE TRYING CONNECT in config *\n"); + LOG (GNUNET_ERROR_TYPE_WARNING, "* Use this only for test purposes. *\n"); + LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n"); + transport_handle = NULL; + } + + + + if (NULL == core_handle) + { + GNUNET_break (0); + GNUNET_SCHEDULER_shutdown (); + return; + } + +} + +/** + * Shut down the peer subsystem. + */ +void +GMP_shutdown (void) +{ + GNUNET_CONTAINER_multipeermap_iterate (peers, &shutdown_tunnel, NULL); + + if (core_handle != NULL) + { + GNUNET_CORE_disconnect (core_handle); + core_handle = NULL; + } + if (transport_handle != NULL) + { + GNUNET_TRANSPORT_disconnect (transport_handle); + transport_handle = NULL; + } + GNUNET_PEER_change_rc (myid, -1); +} + +/** + * Retrieve the CadetPeer stucture associated with the peer, create one + * and insert it in the appropriate structures if the peer is not known yet. + * + * @param peer_id Full identity of the peer. + * + * @return Existing or newly created peer structure. + */ +struct CadetPeer * +GMP_get (const struct GNUNET_PeerIdentity *peer_id) +{ + struct CadetPeer *peer; + + peer = GNUNET_CONTAINER_multipeermap_get (peers, peer_id); + if (NULL == peer) + { + peer = GNUNET_new (struct CadetPeer); + if (GNUNET_CONTAINER_multipeermap_size (peers) > max_peers) + { + peer_delete_oldest (); + } + GNUNET_CONTAINER_multipeermap_put (peers, peer_id, peer, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); + peer->id = GNUNET_PEER_intern (peer_id); + } + peer->last_contact = GNUNET_TIME_absolute_get(); + + return peer; +} + + +/** + * Retrieve the CadetPeer stucture associated with the peer, create one + * and insert it in the appropriate structures if the peer is not known yet. + * + * @param peer Short identity of the peer. + * + * @return Existing or newly created peer structure. + */ +struct CadetPeer * +GMP_get_short (const GNUNET_PEER_Id peer) +{ + return GMP_get (GNUNET_PEER_resolve2 (peer)); +} + + +/** + * Try to connect to a peer on transport level. + * + * @param cls Closure (peer). + * @param tc TaskContext. + */ +static void +try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CadetPeer *peer = cls; + + if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) + return; + + GNUNET_TRANSPORT_try_connect (transport_handle, + GNUNET_PEER_resolve2 (peer->id), NULL, NULL); +} + + +/** + * Try to establish a new connection to this peer (in its tunnel). + * If the peer doesn't have any path to it yet, try to get one. + * If the peer already has some path, send a CREATE CONNECTION towards it. + * + * @param peer Peer to connect to. + */ +void +GMP_connect (struct CadetPeer *peer) +{ + struct CadetTunnel3 *t; + struct CadetPeerPath *p; + struct CadetConnection *c; + int rerun_search; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "peer_connect towards %s\n", GMP_2s (peer)); + + /* If we have a current hello, try to connect using it. */ + GMP_try_connect (peer); + + t = peer->tunnel; + c = NULL; + rerun_search = GNUNET_NO; + + if (NULL != peer->path_head) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " some path exists\n"); + p = peer_get_best_path (peer); + if (NULL != p) + { + char *s; + + s = path_2s (p); + LOG (GNUNET_ERROR_TYPE_DEBUG, " path to use: %s\n", s); + GNUNET_free (s); + + c = GMT_use_path (t, p); + if (NULL == c) + { + /* This case can happen when the path includes a first hop that is + * not yet known to be connected. + * + * This happens quite often during testing when running cadet + * under valgrind: core connect notifications come very late and the + * DHT result has already come and created a valid path. + * In this case, the peer->connections hashmap will be NULL and + * tunnel_use_path will not be able to create a connection from that + * path. + * + * Re-running the DHT GET should give core time to callback. + * + * GMT_use_path -> GMC_new -> register_neighbors takes care of + * updating statistics about this issue. + */ + rerun_search = GNUNET_YES; + } + else + { + GMC_send_create (c); + return; + } + } + else + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " but is NULL, all paths are in use\n"); + } + } + + if (NULL != peer->search_h && GNUNET_YES == rerun_search) + { + GMD_search_stop (peer->search_h); + peer->search_h = NULL; + LOG (GNUNET_ERROR_TYPE_DEBUG, + " Stopping DHT GET for peer %s\n", + GMP_2s (peer)); + } + + if (NULL == peer->search_h) + { + const struct GNUNET_PeerIdentity *id; + + id = GNUNET_PEER_resolve2 (peer->id); + LOG (GNUNET_ERROR_TYPE_DEBUG, + " Starting DHT GET for peer %s\n", GMP_2s (peer)); + peer->search_h = GMD_search (id, &search_handler, peer); + if (CADET_TUNNEL3_NEW == GMT_get_cstate (t)) + GMT_change_cstate (t, CADET_TUNNEL3_SEARCHING); + } +} + + +/** + * Chech whether there is a direct (core level) connection to peer. + * + * @param peer Peer to check. + * + * @return #GNUNET_YES if there is a direct connection. + */ +int +GMP_is_neighbor (const struct CadetPeer *peer) +{ + struct CadetPeerPath *path; + + if (NULL == peer->connections) + return GNUNET_NO; + + for (path = peer->path_head; NULL != path; path = path->next) + { + if (3 > path->length) + return GNUNET_YES; + } + + /* Is not a neighbor but connections is not NULL, probably disconnecting */ + return GNUNET_NO; +} + + +/** + * Create and initialize a new tunnel towards a peer, in case it has none. + * In case the peer already has a tunnel, nothing is done. + * + * Does not generate any traffic, just creates the local data structures. + * + * @param peer Peer towards which to create the tunnel. + */ +void +GMP_add_tunnel (struct CadetPeer *peer) +{ + if (NULL != peer->tunnel) + return; + peer->tunnel = GMT_new (peer); +} + + +/** + * Add a connection to a neighboring peer. + * + * Store that the peer is the first hop of the connection in one + * direction and that on peer disconnect the connection must be + * notified and destroyed, for it will no longer be valid. + * + * @param peer Peer to add connection to. + * @param c Connection to add. + * + * @return GNUNET_OK on success. + */ +int +GMP_add_connection (struct CadetPeer *peer, + struct CadetConnection *c) +{ + int result; + LOG (GNUNET_ERROR_TYPE_DEBUG, "adding connection %s\n", GMC_2s (c)); + LOG (GNUNET_ERROR_TYPE_DEBUG, "to peer %s\n", GMP_2s (peer)); + + if (NULL == peer->connections) + { + GNUNET_break (0); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Peer %s is not a neighbor!\n", + GMP_2s (peer)); + return GNUNET_SYSERR; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "peer %s ok, has %u connections.\n", + GMP_2s (peer), GNUNET_CONTAINER_multihashmap_size (peer->connections)); + result = GNUNET_CONTAINER_multihashmap_put (peer->connections, + GMC_get_h (c), + c, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); + LOG (GNUNET_ERROR_TYPE_DEBUG, + " now has %u connections.\n", + GNUNET_CONTAINER_multihashmap_size (peer->connections)); + LOG (GNUNET_ERROR_TYPE_DEBUG, "result %u\n", result); + + return result; +} + + +/** + * Add the path to the peer and update the path used to reach it in case this + * is the shortest. + * + * @param peer Destination peer to add the path to. + * @param path New path to add. Last peer must be the peer in arg 1. + * Path will be either used of freed if already known. + * @param trusted Do we trust that this path is real? + * + * @return path if path was taken, pointer to existing duplicate if exists + * NULL on error. + */ +struct CadetPeerPath * +GMP_add_path (struct CadetPeer *peer, struct CadetPeerPath *path, + int trusted) +{ + struct CadetPeerPath *aux; + unsigned int l; + unsigned int l2; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "adding path [%u] to peer %s\n", + path->length, GMP_2s (peer)); + + if ((NULL == peer) || (NULL == path)) + { + GNUNET_break (0); + path_destroy (path); + return NULL; + } + if (path->peers[path->length - 1] != peer->id) + { + GNUNET_break (0); + path_destroy (path); + return NULL; + } + + for (l = 1; l < path->length; l++) + { + if (path->peers[l] == myid) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " shortening path by %u\n", l); + for (l2 = 0; l2 < path->length - l; l2++) + { + path->peers[l2] = path->peers[l + l2]; + } + path->length -= l; + l = 1; + path->peers = GNUNET_realloc (path->peers, + path->length * sizeof (GNUNET_PEER_Id)); + } + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, " final length: %u\n", path->length); + + if (2 >= path->length && GNUNET_NO == trusted) + { + /* Only allow CORE to tell us about direct paths */ + path_destroy (path); + return NULL; + } + + l = path_get_length (path); + if (0 == l) + { + path_destroy (path); + return NULL; + } + + GNUNET_assert (peer->id == path->peers[path->length - 1]); + for (aux = peer->path_head; aux != NULL; aux = aux->next) + { + l2 = path_get_length (aux); + if (l2 > l) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " added\n"); + GNUNET_CONTAINER_DLL_insert_before (peer->path_head, + peer->path_tail, aux, path); + if (NULL != peer->tunnel && 3 < GMT_count_connections (peer->tunnel)) + { + GMP_connect (peer); + } + return path; + } + else + { + if (l2 == l && memcmp (path->peers, aux->peers, l) == 0) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " already known\n"); + path_destroy (path); + return aux; + } + } + } + GNUNET_CONTAINER_DLL_insert_tail (peer->path_head, peer->path_tail, + path); + LOG (GNUNET_ERROR_TYPE_DEBUG, " added last\n"); + if (NULL != peer->tunnel && 3 < GMT_count_connections (peer->tunnel)) + { + GMP_connect (peer); + } + return path; +} + + +/** + * Add the path to the origin peer and update the path used to reach it in case + * this is the shortest. + * The path is given in peer_info -> destination, therefore we turn the path + * upside down first. + * + * @param peer Peer to add the path to, being the origin of the path. + * @param path New path to add after being inversed. + * Path will be either used or freed. + * @param trusted Do we trust that this path is real? + * + * @return path if path was taken, pointer to existing duplicate if exists + * NULL on error. + */ +struct CadetPeerPath * +GMP_add_path_to_origin (struct CadetPeer *peer, + struct CadetPeerPath *path, + int trusted) +{ + if (NULL == path) + return NULL; + path_invert (path); + return GMP_add_path (peer, path, trusted); +} + + +/** + * Adds a path to the info of all the peers in the path + * + * @param p Path to process. + * @param confirmed Whether we know if the path works or not. + */ +void +GMP_add_path_to_all (const struct CadetPeerPath *p, int confirmed) +{ + unsigned int i; + + /* TODO: invert and add */ + for (i = 0; i < p->length && p->peers[i] != myid; i++) /* skip'em */ ; + for (i++; i < p->length; i++) + { + struct CadetPeer *aux; + struct CadetPeerPath *copy; + + aux = GMP_get_short (p->peers[i]); + copy = path_duplicate (p); + copy->length = i + 1; + GMP_add_path (aux, copy, p->length < 3 ? GNUNET_NO : confirmed); + } +} + + +/** + * Remove any path to the peer that has the extact same peers as the one given. + * + * @param peer Peer to remove the path from. + * @param path Path to remove. Is always destroyed . + */ +void +GMP_remove_path (struct CadetPeer *peer, struct CadetPeerPath *path) +{ + struct CadetPeerPath *iter; + struct CadetPeerPath *next; + + GNUNET_assert (myid == path->peers[0]); + GNUNET_assert (peer->id == path->peers[path->length - 1]); + + for (iter = peer->path_head; NULL != iter; iter = next) + { + next = iter->next; + if (0 == memcmp (path->peers, iter->peers, + sizeof (GNUNET_PEER_Id) * path->length)) + { + GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, iter); + if (iter != path) + path_destroy (iter); + } + } + path_destroy (path); +} + + +/** + * Remove a connection from a neighboring peer. + * + * @param peer Peer to remove connection from. + * @param c Connection to remove. + * + * @return GNUNET_OK on success. + */ +int +GMP_remove_connection (struct CadetPeer *peer, + const struct CadetConnection *c) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, "removing connection %s\n", GMC_2s (c)); + LOG (GNUNET_ERROR_TYPE_DEBUG, "from peer %s\n", GMP_2s (peer)); + + if (NULL == peer || NULL == peer->connections) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Peer %s is not a neighbor!\n", + GMP_2s (peer)); + return GNUNET_SYSERR; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "peer %s ok, has %u connections.\n", + GMP_2s (peer), GNUNET_CONTAINER_multihashmap_size (peer->connections)); + + return GNUNET_CONTAINER_multihashmap_remove (peer->connections, + GMC_get_h (c), + c); +} + +/** + * Start the DHT search for new paths towards the peer: we don't have + * enough good connections. + * + * @param peer Destination peer. + */ +void +GMP_start_search (struct CadetPeer *peer) +{ + if (NULL != peer->search_h) + { + GNUNET_break (0); + return; + } + + peer->search_h = GMD_search (GMP_get_id (peer), &search_handler, peer); +} + + +/** + * Stop the DHT search for new paths towards the peer: we already have + * enough good connections. + * + * @param peer Destination peer. + */ +void +GMP_stop_search (struct CadetPeer *peer) +{ + if (NULL == peer->search_h) + { + return; + } + + GMD_search_stop (peer->search_h); + peer->search_h = NULL; +} + + +/** + * Get the Full ID of a peer. + * + * @param peer Peer to get from. + * + * @return Full ID of peer. + */ +const struct GNUNET_PeerIdentity * +GMP_get_id (const struct CadetPeer *peer) +{ + return GNUNET_PEER_resolve2 (peer->id); +} + + +/** + * Get the Short ID of a peer. + * + * @param peer Peer to get from. + * + * @return Short ID of peer. + */ +GNUNET_PEER_Id +GMP_get_short_id (const struct CadetPeer *peer) +{ + return peer->id; +} + + +/** + * Set tunnel. + * + * @param peer Peer. + * @param t Tunnel. + */ +void +GMP_set_tunnel (struct CadetPeer *peer, struct CadetTunnel3 *t) +{ + peer->tunnel = t; + if (NULL == t && NULL != peer->search_h) + { + GMP_stop_search (peer); + } +} + + +/** + * Get the tunnel towards a peer. + * + * @param peer Peer to get from. + * + * @return Tunnel towards peer. + */ +struct CadetTunnel3 * +GMP_get_tunnel (const struct CadetPeer *peer) +{ + return peer->tunnel; +} + + +/** + * Set the hello message. + * + * @param peer Peer whose message to set. + * @param hello Hello message. + */ +void +GMP_set_hello (struct CadetPeer *peer, const struct GNUNET_HELLO_Message *hello) +{ + struct GNUNET_HELLO_Message *old; + size_t size; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "set hello for %s\n", GMP_2s (peer)); + if (NULL == hello) + return; + + old = GMP_get_hello (peer); + if (NULL == old) + { + size = GNUNET_HELLO_size (hello); + LOG (GNUNET_ERROR_TYPE_DEBUG, " new (%u bytes)\n", size); + peer->hello = GNUNET_malloc (size); + memcpy (peer->hello, hello, size); + } + else + { + peer->hello = GNUNET_HELLO_merge (old, hello); + LOG (GNUNET_ERROR_TYPE_DEBUG, " merge into %p (%u bytes)\n", + peer->hello, GNUNET_HELLO_size (hello)); + GNUNET_free (old); + } +} + + +/** + * Get the hello message. + * + * @param peer Peer whose message to get. + * + * @return Hello message. + */ +struct GNUNET_HELLO_Message * +GMP_get_hello (struct CadetPeer *peer) +{ + struct GNUNET_TIME_Absolute expiration; + struct GNUNET_TIME_Relative remaining; + + if (NULL == peer->hello) + return NULL; + + expiration = GNUNET_HELLO_get_last_expiration (peer->hello); + remaining = GNUNET_TIME_absolute_get_remaining (expiration); + if (0 == remaining.rel_value_us) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " get - hello expired on %s\n", + GNUNET_STRINGS_absolute_time_to_string (expiration)); + GNUNET_free (peer->hello); + peer->hello = NULL; + } + return peer->hello; +} + + +/** + * Try to connect to a peer on TRANSPORT level. + * + * @param peer Peer to whom to connect. + */ +void +GMP_try_connect (struct CadetPeer *peer) +{ + struct GNUNET_HELLO_Message *hello; + struct GNUNET_MessageHeader *mh; + + if (NULL == transport_handle) + return; + + hello = GMP_get_hello (peer); + if (NULL == hello) + return; + + mh = GNUNET_HELLO_get_header (hello); + GNUNET_TRANSPORT_offer_hello (transport_handle, mh, try_connect, peer); +} + + +/** + * Notify a peer that a link between two other peers is broken. If any path + * used that link, eliminate it. + * + * @param peer Peer affected by the change. + * @param peer1 Peer whose link is broken. + * @param peer2 Peer whose link is broken. + */ +void +GMP_notify_broken_link (struct CadetPeer *peer, + struct GNUNET_PeerIdentity *peer1, + struct GNUNET_PeerIdentity *peer2) +{ + struct CadetPeerPath *iter; + struct CadetPeerPath *next; + unsigned int i; + GNUNET_PEER_Id p1; + GNUNET_PEER_Id p2; + + p1 = GNUNET_PEER_search (peer1); + p2 = GNUNET_PEER_search (peer2); + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Link %u-%u broken\n", p1, p2); + if (0 == p1 || 0 == p2) + { + /* We don't even know them */ + return; + } + + for (iter = peer->path_head; NULL != iter; iter = next) + { + next = iter->next; + for (i = 0; i < iter->length - 1; i++) + { + if ((iter->peers[i] == p1 && iter->peers[i + 1] == p2) + || (iter->peers[i] == p2 && iter->peers[i + 1] == p1)) + { + char *s; + + s = path_2s (iter); + LOG (GNUNET_ERROR_TYPE_DEBUG, " - invalidating %s\n", s); + GNUNET_free (s); + + path_invalidate (iter); + } + } + } +} + + +/** + * Count the number of known paths toward the peer. + * + * @param peer Peer to get path info. + * + * @return Number of known paths. + */ +unsigned int +GMP_count_paths (const struct CadetPeer *peer) +{ + struct CadetPeerPath *iter; + unsigned int i; + + for (iter = peer->path_head, i = 0; NULL != iter; iter = iter->next) + i++; + + return i; +} + + +/** + * Iterate all known peers. + * + * @param iter Iterator. + * @param cls Closure for @c iter. + */ +void +GMP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls) +{ + GNUNET_CONTAINER_multipeermap_iterate (peers, iter, cls); +} + + +/** + * Get the static string for a peer ID. + * + * @param peer Peer. + * + * @return Static string for it's ID. + */ +const char * +GMP_2s (const struct CadetPeer *peer) +{ + if (NULL == peer) + return "(NULL)"; + return GNUNET_i2s (GNUNET_PEER_resolve2 (peer->id)); +} diff --git a/src/cadet/gnunet-service-cadet_peer.h b/src/cadet/gnunet-service-cadet_peer.h new file mode 100644 index 000000000..9f1146e9f --- /dev/null +++ b/src/cadet/gnunet-service-cadet_peer.h @@ -0,0 +1,418 @@ +/* + This file is part of GNUnet. + (C) 2013 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 cadet/gnunet-service-cadet_peer.h + * @brief cadet service; dealing with remote peers + * @author Bartlomiej Polot + * + * All functions in this file should use the prefix GMP (Gnunet Cadet Peer) + */ + +#ifndef GNUNET_SERVICE_CADET_PEER_H +#define GNUNET_SERVICE_CADET_PEER_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "platform.h" +#include "gnunet_util_lib.h" + +/** + * Struct containing all information regarding a given peer + */ +struct CadetPeer; + +/** + * Struct containing info about a queued transmission to this peer + */ +struct CadetPeerQueue; + +#include "gnunet-service-cadet_connection.h" + +/** + * Callback called when a queued message is sent. + * + * @param cls Closure. + * @param c Connection this message was on. + * @param sent Was it really sent? (Could have been canceled) + * @param type Type of message sent. + * @param pid Packet ID, or 0 if not applicable (create, destroy, etc). + * @param fwd Was this a FWD going message? + * @param size Size of the message. + * @param wait Time spent waiting for core (only the time for THIS message) + */ +typedef void (*GMP_sent) (void *cls, + struct CadetConnection *c, int sent, + uint16_t type, uint32_t pid, int fwd, size_t size, + struct GNUNET_TIME_Relative wait); + +/******************************************************************************/ +/******************************** API ***********************************/ +/******************************************************************************/ + +/** + * Initialize peer subsystem. + * + * @param c Configuration. + */ +void +GMP_init (const struct GNUNET_CONFIGURATION_Handle *c); + +/** + * Shut down the peer subsystem. + */ +void +GMP_shutdown (void); + + +/** + * Retrieve the CadetPeer stucture associated with the peer, create one + * and insert it in the appropriate structures if the peer is not known yet. + * + * @param peer_id Full identity of the peer. + * + * @return Existing or newly created peer structure. + */ +struct CadetPeer * +GMP_get (const struct GNUNET_PeerIdentity *peer_id); + + +/** + * Retrieve the CadetPeer stucture associated with the peer, create one + * and insert it in the appropriate structures if the peer is not known yet. + * + * @param peer Short identity of the peer. + * + * @return Existing or newly created peer structure. + */ +struct CadetPeer * +GMP_get_short (const GNUNET_PEER_Id peer); + +/** + * Try to establish a new connection to this peer (in its tunnel). + * If the peer doesn't have any path to it yet, try to get one. + * If the peer already has some path, send a CREATE CONNECTION towards it. + * + * @param peer Peer to connect to. + */ +void +GMP_connect (struct CadetPeer *peer); + +/** + * Free a transmission that was already queued with all resources + * associated to the request. + * + * @param queue Queue handler to cancel. + * @param clear_cls Is it necessary to free associated cls? + * @param sent Was it really sent? (Could have been canceled) + * @param pid PID, if relevant (was sent and was a payload message). + */ +void +GMP_queue_destroy (struct CadetPeerQueue *queue, int clear_cls, + int sent, uint32_t pid); + +/** + * @brief Queue and pass message to core when possible. + * + * @param peer Peer towards which to queue the message. + * @param cls Closure (@c type dependant). It will be used by queue_send to + * build the message to be sent if not already prebuilt. + * @param type Type of the message, 0 for a raw message. + * @param size Size of the message. + * @param c Connection this message belongs to (cannot be NULL). + * @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!) + * @param cont Continuation to be called once CORE has taken the message. + * @param cont_cls Closure for @c cont. + * + * @return Handle to cancel the message before it is sent. Once cont is called + * message has been sent and therefore the handle is no longer valid. + */ +struct CadetPeerQueue * +GMP_queue_add (struct CadetPeer *peer, void *cls, uint16_t type, + uint16_t payload_type, uint32_t payload_id, + size_t size, struct CadetConnection *c, int fwd, + GMP_sent cont, void *cont_cls); + +/** + * Cancel all queued messages to a peer that belong to a certain connection. + * + * @param peer Peer towards whom to cancel. + * @param c Connection whose queued messages to cancel. Might be destroyed by + * the sent continuation call. + */ +void +GMP_queue_cancel (struct CadetPeer *peer, struct CadetConnection *c); + +/** + * Get the first message for a connection and unqueue it. + * + * @param peer Neighboring peer. + * @param c Connection. + * + * @return First message for this connection. + */ +struct GNUNET_MessageHeader * +GMP_connection_pop (struct CadetPeer *peer, struct CadetConnection *c); + +void +GMP_queue_unlock (struct CadetPeer *peer, struct CadetConnection *c); + +/** + * Set tunnel. + * + * @param peer Peer. + * @param t Tunnel. + */ +void +GMP_set_tunnel (struct CadetPeer *peer, struct CadetTunnel3 *t); + +/** + * Check whether there is a direct (core level) connection to peer. + * + * @param peer Peer to check. + * + * @return #GNUNET_YES if there is a direct connection. + */ +int +GMP_is_neighbor (const struct CadetPeer *peer); + +/** + * Create and initialize a new tunnel towards a peer, in case it has none. + * + * Does not generate any traffic, just creates the local data structures. + * + * @param peer Peer towards which to create the tunnel. + */ +void +GMP_add_tunnel (struct CadetPeer *peer); + +/** + * Add a connection to a neighboring peer. + * + * Store that the peer is the first hop of the connection in one + * direction and that on peer disconnect the connection must be + * notified and destroyed, for it will no longer be valid. + * + * @param peer Peer to add connection to. + * @param c Connection to add. + * + * @return GNUNET_OK on success. + */ +int +GMP_add_connection (struct CadetPeer *peer, struct CadetConnection *c); + +/** + * Add the path to the peer and update the path used to reach it in case this + * is the shortest. + * + * @param peer Destination peer to add the path to. + * @param path New path to add. Last peer must be the peer in arg 1. + * Path will be either used of freed if already known. + * @param trusted Do we trust that this path is real? + * + * @return path if path was taken, pointer to existing duplicate if exists + * NULL on error. + */ +struct CadetPeerPath * +GMP_add_path (struct CadetPeer *peer, struct CadetPeerPath *p, int trusted); + +/** + * Add the path to the origin peer and update the path used to reach it in case + * this is the shortest. + * The path is given in peer_info -> destination, therefore we turn the path + * upside down first. + * + * @param peer Peer to add the path to, being the origin of the path. + * @param path New path to add after being inversed. + * Path will be either used or freed. + * @param trusted Do we trust that this path is real? + * + * @return path if path was taken, pointer to existing duplicate if exists + * NULL on error. + */ +struct CadetPeerPath * +GMP_add_path_to_origin (struct CadetPeer *peer, + struct CadetPeerPath *path, + int trusted); + +/** + * Adds a path to the info of all the peers in the path + * + * @param p Path to process. + * @param confirmed Whether we know if the path works or not. + */ +void +GMP_add_path_to_all (const struct CadetPeerPath *p, int confirmed); + +/** + * Remove any path to the peer that has the extact same peers as the one given. + * + * @param peer Peer to remove the path from. + * @param path Path to remove. Is always destroyed . + */ +void +GMP_remove_path (struct CadetPeer *peer, struct CadetPeerPath *path); + +/** + * Remove a connection from a neighboring peer. + * + * @param peer Peer to remove connection from. + * @param c Connection to remove. + * + * @return GNUNET_OK on success. + */ +int +GMP_remove_connection (struct CadetPeer *peer, const struct CadetConnection *c); + +/** + * Start the DHT search for new paths towards the peer: we don't have + * enough good connections. + * + * @param peer Destination peer. + */ +void +GMP_start_search (struct CadetPeer *peer); + +/** + * Stop the DHT search for new paths towards the peer: we already have + * enough good connections. + * + * @param peer Destination peer. + */ +void +GMP_stop_search (struct CadetPeer *peer); + +/** + * Get the Full ID of a peer. + * + * @param peer Peer to get from. + * + * @return Full ID of peer. + */ +const struct GNUNET_PeerIdentity * +GMP_get_id (const struct CadetPeer *peer); + +/** + * Get the Short ID of a peer. + * + * @param peer Peer to get from. + * + * @return Short ID of peer. + */ +GNUNET_PEER_Id +GMP_get_short_id (const struct CadetPeer *peer); + +/** + * Get the tunnel towards a peer. + * + * @param peer Peer to get from. + * + * @return Tunnel towards peer. + */ +struct CadetTunnel3 * +GMP_get_tunnel (const struct CadetPeer *peer); + +/** + * Set the hello message. + * + * @param peer Peer whose message to set. + * @param hello Hello message. + */ +void +GMP_set_hello (struct CadetPeer *peer, const struct GNUNET_HELLO_Message *hello); + +/** + * Get the hello message. + * + * @param peer Peer whose message to get. + * + * @return Hello message. + */ +struct GNUNET_HELLO_Message * +GMP_get_hello (struct CadetPeer *peer); + + +/** + * Try to connect to a peer on TRANSPORT level. + * + * @param peer Peer to whom to connect. + */ +void +GMP_try_connect (struct CadetPeer *peer); + +/** + * Notify a peer that a link between two other peers is broken. If any path + * used that link, eliminate it. + * + * @param peer Peer affected by the change. + * @param peer1 Peer whose link is broken. + * @param peer2 Peer whose link is broken. + */ +void +GMP_notify_broken_link (struct CadetPeer *peer, + struct GNUNET_PeerIdentity *peer1, + struct GNUNET_PeerIdentity *peer2); + +/** + * Count the number of known paths toward the peer. + * + * @param peer Peer to get path info. + * + * @return Number of known paths. + */ +unsigned int +GMP_count_paths (const struct CadetPeer *peer); + +/** + * Iterate all known peers. + * + * @param iter Iterator. + * @param cls Closure for @c iter. + */ +void +GMP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls); + +/** + * Get the static string for a peer ID. + * + * @param peer Peer. + * + * @return Static string for it's ID. + */ +const char * +GMP_2s (const struct CadetPeer *peer); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_CADET_SERVICE_PEER_H */ +#endif +/* end of gnunet-cadet-service_peer.h */ diff --git a/src/cadet/gnunet-service-cadet_tunnel.c b/src/cadet/gnunet-service-cadet_tunnel.c new file mode 100644 index 000000000..f2be27bf5 --- /dev/null +++ b/src/cadet/gnunet-service-cadet_tunnel.c @@ -0,0 +1,2887 @@ +/* + This file is part of GNUnet. + (C) 2013 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_util_lib.h" + +#include "gnunet_signatures.h" +#include "gnunet_statistics_service.h" + +#include "cadet_protocol.h" +#include "cadet_path.h" + +#include "gnunet-service-cadet_tunnel.h" +#include "gnunet-service-cadet_connection.h" +#include "gnunet-service-cadet_channel.h" +#include "gnunet-service-cadet_peer.h" + +#define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__) + +#define REKEY_WAIT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5) + +#define CONNECTIONS_PER_TUNNEL 3 + +/******************************************************************************/ +/******************************** STRUCTS **********************************/ +/******************************************************************************/ + +struct CadetTChannel +{ + struct CadetTChannel *next; + struct CadetTChannel *prev; + struct CadetChannel *ch; +}; + + +/** + * Connection list and metadata. + */ +struct CadetTConnection +{ + /** + * Next in DLL. + */ + struct CadetTConnection *next; + + /** + * Prev in DLL. + */ + struct CadetTConnection *prev; + + /** + * Connection handle. + */ + struct CadetConnection *c; + + /** + * Creation time, to keep oldest connection alive. + */ + struct GNUNET_TIME_Absolute created; + + /** + * Connection throughput, to keep fastest connection alive. + */ + uint32_t throughput; +}; + +/** + * Structure used during a Key eXchange. + */ +struct CadetTunnelKXCtx +{ + /** + * Decryption ("their") old key, for decrypting traffic sent by the + * other end before the key exchange started. + */ + struct GNUNET_CRYPTO_SymmetricSessionKey d_key_old; + + /** + * Challenge to send in a ping and expect in the pong. + */ + uint32_t challenge; +}; + +/** + * Struct containing all information regarding a tunnel to a peer. + */ +struct CadetTunnel3 +{ + /** + * Endpoint of the tunnel. + */ + struct CadetPeer *peer; + + /** + * State of the tunnel connectivity. + */ + enum CadetTunnel3CState cstate; + + /** + * State of the tunnel encryption. + */ + enum CadetTunnel3EState estate; + + /** + * Key eXchange context. + */ + struct CadetTunnelKXCtx *kx_ctx; + + /** + * Encryption ("our") key. + */ + struct GNUNET_CRYPTO_SymmetricSessionKey e_key; + + /** + * Decryption ("their") key. + */ + struct GNUNET_CRYPTO_SymmetricSessionKey d_key; + + /** + * Task to start the rekey process. + */ + GNUNET_SCHEDULER_TaskIdentifier rekey_task; + + /** + * Paths that are actively used to reach the destination peer. + */ + struct CadetTConnection *connection_head; + struct CadetTConnection *connection_tail; + + /** + * Next connection number. + */ + uint32_t next_cid; + + /** + * Channels inside this tunnel. + */ + struct CadetTChannel *channel_head; + struct CadetTChannel *channel_tail; + + /** + * Channel ID for the next created channel. + */ + CADET_ChannelNumber next_chid; + + /** + * Destroy flag: if true, destroy on last message. + */ + GNUNET_SCHEDULER_TaskIdentifier destroy_task; + + /** + * Queued messages, to transmit once tunnel gets connected. + */ + struct CadetTunnelDelayed *tq_head; + struct CadetTunnelDelayed *tq_tail; +}; + + +/** + * Struct used to save messages in a non-ready tunnel to send once connected. + */ +struct CadetTunnelDelayed +{ + /** + * DLL + */ + struct CadetTunnelDelayed *next; + struct CadetTunnelDelayed *prev; + + /** + * Tunnel. + */ + struct CadetTunnel3 *t; + + /** + * Tunnel queue given to the channel to cancel request. Update on send_queued. + */ + struct CadetTunnel3Queue *tq; + + /** + * Message to send. + */ + /* struct GNUNET_MessageHeader *msg; */ +}; + + +/** + * Handle for messages queued but not yet sent. + */ +struct CadetTunnel3Queue +{ + /** + * Connection queue handle, to cancel if necessary. + */ + struct CadetConnectionQueue *cq; + + /** + * Handle in case message hasn't been given to a connection yet. + */ + struct CadetTunnelDelayed *tqd; + + /** + * Continuation to call once sent. + */ + GMT_sent cont; + + /** + * Closure for @c cont. + */ + void *cont_cls; +}; + + +/******************************************************************************/ +/******************************* GLOBALS ***********************************/ +/******************************************************************************/ + +/** + * Global handle to the statistics service. + */ +extern struct GNUNET_STATISTICS_Handle *stats; + +/** + * Local peer own ID (memory efficient handle). + */ +extern GNUNET_PEER_Id myid; + +/** + * Local peer own ID (full value). + */ +extern struct GNUNET_PeerIdentity my_full_id; + + +/** + * Don't try to recover tunnels if shutting down. + */ +extern int shutting_down; + + +/** + * Set of all tunnels, in order to trigger a new exchange on rekey. + * Indexed by peer's ID. + */ +static struct GNUNET_CONTAINER_MultiPeerMap *tunnels; + +/** + * Default TTL for payload packets. + */ +static unsigned long long default_ttl; + +/** + * Own private key. + */ +const static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key; + +/** + * Own ephemeral private key. + */ +static struct GNUNET_CRYPTO_EcdhePrivateKey *my_ephemeral_key; + +/** + * Cached message used to perform a key exchange. + */ +static struct GNUNET_CADET_KX_Ephemeral kx_msg; + +/** + * Task to generate a new ephemeral key. + */ +static GNUNET_SCHEDULER_TaskIdentifier rekey_task; + +/** + * Rekey period. + */ +static struct GNUNET_TIME_Relative rekey_period; + +/******************************************************************************/ +/******************************** STATIC ***********************************/ +/******************************************************************************/ + +/** + * Get string description for tunnel connectivity state. + * + * @param cs Tunnel state. + * + * @return String representation. + */ +static const char * +cstate2s (enum CadetTunnel3CState cs) +{ + static char buf[128]; + + switch (cs) + { + case CADET_TUNNEL3_NEW: + return "CADET_TUNNEL3_NEW"; + case CADET_TUNNEL3_SEARCHING: + return "CADET_TUNNEL3_SEARCHING"; + case CADET_TUNNEL3_WAITING: + return "CADET_TUNNEL3_WAITING"; + case CADET_TUNNEL3_READY: + return "CADET_TUNNEL3_READY"; + + default: + sprintf (buf, "%u (UNKNOWN STATE)", cs); + return buf; + } + return ""; +} + + +/** + * Get string description for tunnel encryption state. + * + * @param es Tunnel state. + * + * @return String representation. + */ +static const char * +estate2s (enum CadetTunnel3EState es) +{ + static char buf[128]; + + switch (es) + { + case CADET_TUNNEL3_KEY_UNINITIALIZED: + return "CADET_TUNNEL3_KEY_UNINITIALIZED"; + case CADET_TUNNEL3_KEY_SENT: + return "CADET_TUNNEL3_KEY_SENT"; + case CADET_TUNNEL3_KEY_PING: + return "CADET_TUNNEL3_KEY_PING"; + case CADET_TUNNEL3_KEY_OK: + return "CADET_TUNNEL3_KEY_OK"; + + default: + sprintf (buf, "%u (UNKNOWN STATE)", es); + return buf; + } + return ""; +} + + +/** + * @brief Check if tunnel is ready to send traffic. + * + * Tunnel must be connected and with encryption correctly set up. + * + * @param t Tunnel to check. + * + * @return #GNUNET_YES if ready, #GNUNET_NO otherwise + */ +static int +is_ready (struct CadetTunnel3 *t) +{ + int ready; + + GMT_debug (t); + ready = (CADET_TUNNEL3_READY == t->cstate && CADET_TUNNEL3_KEY_OK == t->estate); + ready = ready || GMT_is_loopback (t); + return ready; +} + + +/** + * Ephemeral key message purpose size. + * + * @return Size of the part of the ephemeral key message that must be signed. + */ +size_t +ephemeral_purpose_size (void) +{ + return sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + + sizeof (struct GNUNET_TIME_AbsoluteNBO) + + sizeof (struct GNUNET_TIME_AbsoluteNBO) + + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + + sizeof (struct GNUNET_PeerIdentity); +} + + +/** + * Size of the encrypted part of a ping message. + * + * @return Size of the encrypted part of a ping message. + */ +size_t +ping_encryption_size (void) +{ + return sizeof (struct GNUNET_PeerIdentity) + sizeof (uint32_t); +} + + +/** + * Get the channel's buffer. ONLY FOR NON-LOOPBACK CHANNELS!! + * + * @param tch Tunnel's channel handle. + * + * @return Amount of messages the channel can still buffer towards the client. + */ +static unsigned int +get_channel_buffer (const struct CadetTChannel *tch) +{ + int fwd; + + /* If channel is outgoing, is origin in the FWD direction and fwd is YES */ + fwd = GMCH_is_origin (tch->ch, GNUNET_YES); + + return GMCH_get_buffer (tch->ch, fwd); +} + + +/** + * Get the channel's allowance status. + * + * @param tch Tunnel's channel handle. + * + * @return #GNUNET_YES if we allowed the client to send data to us. + */ +static int +get_channel_allowed (const struct CadetTChannel *tch) +{ + int fwd; + + /* If channel is outgoing, is origin in the FWD direction and fwd is YES */ + fwd = GMCH_is_origin (tch->ch, GNUNET_YES); + + return GMCH_get_allowed (tch->ch, fwd); +} + + +/** + * Get the connection's buffer. + * + * @param tc Tunnel's connection handle. + * + * @return Amount of messages the connection can still buffer. + */ +static unsigned int +get_connection_buffer (const struct CadetTConnection *tc) +{ + int fwd; + + /* If connection is outgoing, is origin in the FWD direction and fwd is YES */ + fwd = GMC_is_origin (tc->c, GNUNET_YES); + + return GMC_get_buffer (tc->c, fwd); +} + + +/** + * Get the connection's allowance. + * + * @param tc Tunnel's connection handle. + * + * @return Amount of messages we have allowed the next peer to send us. + */ +static unsigned int +get_connection_allowed (const struct CadetTConnection *tc) +{ + int fwd; + + /* If connection is outgoing, is origin in the FWD direction and fwd is YES */ + fwd = GMC_is_origin (tc->c, GNUNET_YES); + + return GMC_get_allowed (tc->c, fwd); +} + + +/** + * Check that a ephemeral key message s well formed and correctly signed. + * + * @param t Tunnel on which the message came. + * @param msg The ephemeral key message. + * + * @return GNUNET_OK if message is fine, GNUNET_SYSERR otherwise. + */ +int +check_ephemeral (struct CadetTunnel3 *t, + const struct GNUNET_CADET_KX_Ephemeral *msg) +{ + /* Check message size */ + if (ntohs (msg->header.size) != sizeof (struct GNUNET_CADET_KX_Ephemeral)) + return GNUNET_SYSERR; + + /* Check signature size */ + if (ntohl (msg->purpose.size) != ephemeral_purpose_size ()) + return GNUNET_SYSERR; + + /* Check origin */ + if (0 != memcmp (&msg->origin_identity, + GMP_get_id (t->peer), + sizeof (struct GNUNET_PeerIdentity))) + return GNUNET_SYSERR; + + /* Check signature */ + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_CADET_KX, + &msg->purpose, + &msg->signature, + &msg->origin_identity.public_key)) + return GNUNET_SYSERR; + + return GNUNET_OK; +} + + +/** + * Encrypt data with the tunnel key. + * + * @param t Tunnel whose key to use. + * @param dst Destination for the encrypted data. + * @param src Source of the plaintext. Can overlap with @c dst. + * @param size Size of the plaintext. + * @param iv Initialization Vector to use. + */ +static int +t_encrypt (struct CadetTunnel3 *t, + void *dst, const void *src, + size_t size, uint32_t iv) +{ + struct GNUNET_CRYPTO_SymmetricInitializationVector siv; + size_t out_size; + + LOG (GNUNET_ERROR_TYPE_DEBUG, " t_encrypt start\n"); + GNUNET_CRYPTO_symmetric_derive_iv (&siv, &t->e_key, &iv, sizeof (iv), NULL); + LOG (GNUNET_ERROR_TYPE_DEBUG, " t_encrypt IV derived\n"); + out_size = GNUNET_CRYPTO_symmetric_encrypt (src, size, &t->e_key, &siv, dst); + LOG (GNUNET_ERROR_TYPE_DEBUG, " t_encrypt end\n"); + + return out_size; +} + + +/** + * Decrypt data with the tunnel key. + * + * @param t Tunnel whose key to use. + * @param dst Destination for the plaintext. + * @param src Source of the encrypted data. Can overlap with @c dst. + * @param size Size of the encrypted data. + * @param iv Initialization Vector to use. + */ +static int +t_decrypt (struct CadetTunnel3 *t, + void *dst, const void *src, + size_t size, uint32_t iv) +{ + struct GNUNET_CRYPTO_SymmetricInitializationVector siv; + struct GNUNET_CRYPTO_SymmetricSessionKey *key; + size_t out_size; + + LOG (GNUNET_ERROR_TYPE_DEBUG, " t_decrypt start\n"); + if (t->estate == CADET_TUNNEL3_KEY_OK || t->estate == CADET_TUNNEL3_KEY_PING) + { + key = &t->d_key; + } + else if (NULL != t->kx_ctx) + { + key = &t->kx_ctx->d_key_old; + } + else + { + GNUNET_STATISTICS_update (stats, "# non decryptable data", 1, GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "WARNING got data on %s without a valid key\n", + GMT_2s (t)); + GMT_debug (t); + return 0; + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, " t_decrypt iv\n"); + GNUNET_CRYPTO_symmetric_derive_iv (&siv, key, &iv, sizeof (iv), NULL); + LOG (GNUNET_ERROR_TYPE_DEBUG, " t_decrypt iv done\n"); + out_size = GNUNET_CRYPTO_symmetric_decrypt (src, size, key, &siv, dst); + LOG (GNUNET_ERROR_TYPE_DEBUG, " t_decrypt end\n"); + + return out_size; +} + + +/** + * Create key material by doing ECDH on the local and remote ephemeral keys. + * + * @param key_material Where to store the key material. + * @param ephemeral_key Peer's public ephemeral key. + */ +void +derive_key_material (struct GNUNET_HashCode *key_material, + const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key) +{ + if (GNUNET_OK != + GNUNET_CRYPTO_ecc_ecdh (my_ephemeral_key, + ephemeral_key, + key_material)) + { + GNUNET_break (0); + } +} + +/** + * Create a symmetic key from the identities of both ends and the key material + * from ECDH. + * + * @param key Destination for the generated key. + * @param sender ID of the peer that will encrypt with @c key. + * @param receiver ID of the peer that will decrypt with @c key. + * @param key_material Hash created with ECDH with the ephemeral keys. + */ +void +derive_symmertic (struct GNUNET_CRYPTO_SymmetricSessionKey *key, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_PeerIdentity *receiver, + const struct GNUNET_HashCode *key_material) +{ + const char salt[] = "CADET kx salt"; + + GNUNET_CRYPTO_kdf (key, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey), + salt, sizeof (salt), + key_material, sizeof (struct GNUNET_HashCode), + sender, sizeof (struct GNUNET_PeerIdentity), + receiver, sizeof (struct GNUNET_PeerIdentity), + NULL); +} + +/** + * Pick a connection on which send the next data message. + * + * @param t Tunnel on which to send the message. + * + * @return The connection on which to send the next message. + */ +static struct CadetConnection * +tunnel_get_connection (struct CadetTunnel3 *t) +{ + struct CadetTConnection *iter; + struct CadetConnection *best; + unsigned int qn; + unsigned int lowest_q; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel_get_connection %s\n", GMT_2s (t)); + best = NULL; + lowest_q = UINT_MAX; + for (iter = t->connection_head; NULL != iter; iter = iter->next) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " connection %s: %u\n", + GMC_2s (iter->c), GMC_get_state (iter->c)); + if (CADET_CONNECTION_READY == GMC_get_state (iter->c)) + { + qn = GMC_get_qn (iter->c, GMC_is_origin (iter->c, GNUNET_YES)); + LOG (GNUNET_ERROR_TYPE_DEBUG, " q_n %u, \n", qn); + if (qn < lowest_q) + { + best = iter->c; + lowest_q = qn; + } + } + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " selected: connection %s\n", GMC_2s (best)); + return best; +} + + +/** + * Callback called when a queued message is sent. + * + * Calculates the average time and connection packet tracking. + * + * @param cls Closure (TunnelQueue handle). + * @param c Connection this message was on. + * @param q Connection queue handle (unused). + * @param type Type of message sent. + * @param fwd Was this a FWD going message? + * @param size Size of the message. + */ +static void +tun_message_sent (void *cls, + struct CadetConnection *c, + struct CadetConnectionQueue *q, + uint16_t type, int fwd, size_t size) +{ + struct CadetTunnel3Queue *qt = cls; + struct CadetTunnel3 *t; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "tun_message_sent\n"); + + GNUNET_assert (NULL != qt->cont); + t = NULL == c ? NULL : GMC_get_tunnel (c); + qt->cont (qt->cont_cls, t, qt, type, size); + GNUNET_free (qt); +} + + +/** + * Delete a queued message: either was sent or the channel was destroyed + * before the tunnel's key exchange had a chance to finish. + * + * @param tqd Delayed queue handle. + */ +static void +unqueue_data (struct CadetTunnelDelayed *tqd) +{ + GNUNET_CONTAINER_DLL_remove (tqd->t->tq_head, tqd->t->tq_tail, tqd); + GNUNET_free (tqd); +} + + +/** + * Cache a message to be sent once tunnel is online. + * + * @param t Tunnel to hold the message. + * @param msg Message itself (copy will be made). + */ +static struct CadetTunnelDelayed * +queue_data (struct CadetTunnel3 *t, const struct GNUNET_MessageHeader *msg) +{ + struct CadetTunnelDelayed *tqd; + uint16_t size = ntohs (msg->size); + + LOG (GNUNET_ERROR_TYPE_DEBUG, "queue data on Tunnel %s\n", GMT_2s (t)); + + if (GNUNET_YES == is_ready (t)) + { + GNUNET_break (0); + return NULL; + } + + tqd = GNUNET_malloc (sizeof (struct CadetTunnelDelayed) + size); + + tqd->t = t; + memcpy (&tqd[1], msg, size); + GNUNET_CONTAINER_DLL_insert_tail (t->tq_head, t->tq_tail, tqd); + return tqd; +} + + +/** + * Calculate HMAC. + * + * @param t Tunnel to get keys from. + * @param plaintext Content to HMAC. + * @param size Size of @c plaintext. + * @param iv Initialization vector for the message. + * @param outgoing Is this an outgoing message that we encrypted? + * @param hmac Destination to store the HMAC. + */ +static void +t_hmac (struct CadetTunnel3 *t, const void *plaintext, size_t size, uint32_t iv, + int outgoing, struct GNUNET_CADET_Hash *hmac) +{ + struct GNUNET_CRYPTO_AuthKey auth_key; + static const char ctx[] = "cadet authentication key"; + struct GNUNET_CRYPTO_SymmetricSessionKey *key; + struct GNUNET_HashCode hash; + + key = outgoing ? &t->e_key : &t->d_key; + GNUNET_CRYPTO_hmac_derive_key (&auth_key, key, + &iv, sizeof (iv), + key, sizeof (*key), + ctx, sizeof (ctx), + NULL); + GNUNET_CRYPTO_hmac (&auth_key, plaintext, size, &hash); + memcpy (hmac, &hash, sizeof (*hmac)); +} + + +/** + * Sends an already built message on a tunnel, encrypting it and + * choosing the best connection. + * + * @param message Message to send. Function modifies it. + * @param t Tunnel on which this message is transmitted. + * @param c Connection to use (autoselect if NULL). + * @param force Force the tunnel to take the message (buffer overfill). + * @param cont Continuation to call once message is really sent. + * @param cont_cls Closure for @c cont. + * @param existing_q In case this a transmission of previously queued data, + * this should be TunnelQueue given to the client. + * Otherwise, NULL. + * + * @return Handle to cancel message. NULL if @c cont is NULL. + */ +static struct CadetTunnel3Queue * +send_prebuilt_message (const struct GNUNET_MessageHeader *message, + struct CadetTunnel3 *t, struct CadetConnection *c, + int force, GMT_sent cont, void *cont_cls, + struct CadetTunnel3Queue *existing_q) +{ + struct CadetTunnel3Queue *tq; + struct GNUNET_CADET_Encrypted *msg; + size_t size = ntohs (message->size); + char cbuf[sizeof (struct GNUNET_CADET_Encrypted) + size]; + uint32_t mid; + uint32_t iv; + uint16_t type; + int fwd; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT Send on Tunnel %s\n", GMT_2s (t)); + + if (GNUNET_NO == is_ready (t)) + { + struct CadetTunnelDelayed *tqd; + /* A non null existing_q indicates sending of queued data. + * Should only happen after tunnel becomes ready. + */ + GNUNET_assert (NULL == existing_q); + tqd = queue_data (t, message); + if (NULL == cont) + return NULL; + tq = GNUNET_new (struct CadetTunnel3Queue); + tq->tqd = tqd; + tqd->tq = tq; + tq->cont = cont; + tq->cont_cls = cont_cls; + return tq; + } + + GNUNET_assert (GNUNET_NO == GMT_is_loopback (t)); + + iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); + msg = (struct GNUNET_CADET_Encrypted *) cbuf; + msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED); + msg->iv = iv; + GNUNET_assert (t_encrypt (t, &msg[1], message, size, iv) == size); + t_hmac (t, &msg[1], size, iv, GNUNET_YES, &msg->hmac); + msg->header.size = htons (sizeof (struct GNUNET_CADET_Encrypted) + size); + + if (NULL == c) + c = tunnel_get_connection (t); + if (NULL == c) + { + if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task + || CADET_TUNNEL3_SEARCHING != t->cstate) + { + GNUNET_break (0); + GMT_debug (t); + } + return NULL; + } + + mid = 0; + type = ntohs (message->type); + switch (type) + { + case GNUNET_MESSAGE_TYPE_CADET_DATA: + case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK: + if (GNUNET_MESSAGE_TYPE_CADET_DATA == type) + mid = ntohl (((struct GNUNET_CADET_Data *) message)->mid); + else + mid = ntohl (((struct GNUNET_CADET_DataACK *) message)->mid); + /* Fall thru */ + case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE: + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE: + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK: + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK: + msg->cid = *GMC_get_id (c); + msg->ttl = htonl (default_ttl); + break; + default: + GNUNET_break (0); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "type %s\n", GM_m2s (type)); + + fwd = GMC_is_origin (c, GNUNET_YES); + + if (NULL == cont) + { + GNUNET_break (NULL == + GMC_send_prebuilt_message (&msg->header, type, mid, + c, fwd, force, NULL, NULL)); + return NULL; + } + if (NULL == existing_q) + { + tq = GNUNET_new (struct CadetTunnel3Queue); /* FIXME valgrind: leak*/ + } + else + { + tq = existing_q; + tq->tqd = NULL; + } + tq->cq = GMC_send_prebuilt_message (&msg->header, type, mid, c, fwd, force, + &tun_message_sent, tq); + tq->cont = cont; + tq->cont_cls = cont_cls; + + return tq; +} + + +/** + * Send all cached messages that we can, tunnel is online. + * + * @param t Tunnel that holds the messages. Cannot be loopback. + */ +static void +send_queued_data (struct CadetTunnel3 *t) +{ + struct CadetTunnelDelayed *tqd; + struct CadetTunnelDelayed *next; + unsigned int room; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "GMT_send_queued_data on tunnel %s\n", + GMT_2s (t)); + + if (GMT_is_loopback (t)) + { + GNUNET_break (0); + return; + } + + if (GNUNET_NO == is_ready (t)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " not ready yet: %s/%s\n", + estate2s (t->estate), cstate2s (t->cstate)); + return; + } + + room = GMT_get_connections_buffer (t); + LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space: %u\n", room); + LOG (GNUNET_ERROR_TYPE_DEBUG, " tq head: %p\n", t->tq_head); + for (tqd = t->tq_head; NULL != tqd && room > 0; tqd = next) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " sending queued data\n"); + next = tqd->next; + room--; + send_prebuilt_message ((struct GNUNET_MessageHeader *) &tqd[1], + tqd->t, NULL, GNUNET_YES, + NULL != tqd->tq ? tqd->tq->cont : NULL, + NULL != tqd->tq ? tqd->tq->cont_cls : NULL, + tqd->tq); + unqueue_data (tqd); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT_send_queued_data end\n", GMP_2s (t->peer)); +} + + +/** + * Sends key exchange message on a tunnel, choosing the best connection. + * Should not be called on loopback tunnels. + * + * @param t Tunnel on which this message is transmitted. + * @param message Message to send. Function modifies it. + */ +static void +send_kx (struct CadetTunnel3 *t, + const struct GNUNET_MessageHeader *message) +{ + struct CadetConnection *c; + struct GNUNET_CADET_KX *msg; + size_t size = ntohs (message->size); + char cbuf[sizeof (struct GNUNET_CADET_KX) + size]; + uint16_t type; + int fwd; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT KX on Tunnel %s\n", GMT_2s (t)); + + /* Avoid loopback. */ + if (GMT_is_loopback (t)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " loopback!\n"); + GNUNET_break (0); + return; + } + + if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " being destroyed, why bother\n"); + return; + } + + /* Must have a connection. */ + if (NULL == t->connection_head) + { + GNUNET_break (CADET_TUNNEL3_SEARCHING == t->cstate); + GMT_debug (t); + return; + } + + msg = (struct GNUNET_CADET_KX *) cbuf; + msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_KX); + msg->header.size = htons (sizeof (struct GNUNET_CADET_KX) + size); + c = tunnel_get_connection (t); + if (NULL == c) + { + GNUNET_break (GNUNET_SCHEDULER_NO_TASK != t->destroy_task + || CADET_TUNNEL3_READY != t->cstate); + GMT_debug (t); + return; + } + type = ntohs (message->type); + switch (type) + { + case GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL: + case GNUNET_MESSAGE_TYPE_CADET_KX_PING: + case GNUNET_MESSAGE_TYPE_CADET_KX_PONG: + memcpy (&msg[1], message, size); + break; + default: + LOG (GNUNET_ERROR_TYPE_DEBUG, "unkown type %s\n", + GM_m2s (type)); + GNUNET_break (0); + } + + fwd = GMC_is_origin (t->connection_head->c, GNUNET_YES); + /* TODO save handle and cancel in case of a unneeded retransmission */ + GMC_send_prebuilt_message (&msg->header, GNUNET_MESSAGE_TYPE_CADET_KX, + message->type, c, fwd, GNUNET_YES, NULL, NULL); +} + + +/** + * Send the ephemeral key on a tunnel. + * + * @param t Tunnel on which to send the key. + */ +static void +send_ephemeral (struct CadetTunnel3 *t) +{ + LOG (GNUNET_ERROR_TYPE_INFO, "=> EPHM for %s\n", GMT_2s (t)); + + kx_msg.sender_status = htonl (t->estate); + send_kx (t, &kx_msg.header); +} + +/** + * Send a ping message on a tunnel. + * + * @param t Tunnel on which to send the ping. + */ +static void +send_ping (struct CadetTunnel3 *t) +{ + struct GNUNET_CADET_KX_Ping msg; + + LOG (GNUNET_ERROR_TYPE_INFO, "=> PING for %s\n", GMT_2s (t)); + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_KX_PING); + msg.iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); + msg.target = *GMP_get_id (t->peer); + msg.nonce = t->kx_ctx->challenge; + + LOG (GNUNET_ERROR_TYPE_DEBUG, " sending %u\n", msg.nonce); + LOG (GNUNET_ERROR_TYPE_DEBUG, " towards %s\n", GNUNET_i2s (&msg.target)); + t_encrypt (t, &msg.target, &msg.target, ping_encryption_size(), msg.iv); + LOG (GNUNET_ERROR_TYPE_DEBUG, " e sending %u\n", msg.nonce); + LOG (GNUNET_ERROR_TYPE_DEBUG, " e towards %s\n", GNUNET_i2s (&msg.target)); + + send_kx (t, &msg.header); +} + + +/** + * Send a pong message on a tunnel. + * + * @param t Tunnel on which to send the pong. + * @param challenge Value sent in the ping that we have to send back. + */ +static void +send_pong (struct CadetTunnel3 *t, uint32_t challenge) +{ + struct GNUNET_CADET_KX_Pong msg; + + LOG (GNUNET_ERROR_TYPE_INFO, "=> PONG for %s\n", GMT_2s (t)); + msg.header.size = htons (sizeof (msg)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_KX_PONG); + msg.iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); + msg.nonce = challenge; + LOG (GNUNET_ERROR_TYPE_DEBUG, " sending %u\n", msg.nonce); + t_encrypt (t, &msg.nonce, &msg.nonce, sizeof (msg.nonce), msg.iv); + LOG (GNUNET_ERROR_TYPE_DEBUG, " e sending %u\n", msg.nonce); + + send_kx (t, &msg.header); +} + + +/** + * Initiate a rekey with the remote peer. + * + * @param cls Closure (tunnel). + * @param tc TaskContext. + */ +static void +rekey_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CadetTunnel3 *t = cls; + + t->rekey_task = GNUNET_SCHEDULER_NO_TASK; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Re-key Tunnel %s\n", GMT_2s (t)); + if (NULL != tc && 0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) + return; + + if (NULL == t->kx_ctx) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " new kx ctx\n"); + t->kx_ctx = GNUNET_new (struct CadetTunnelKXCtx); + t->kx_ctx->challenge = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); + t->kx_ctx->d_key_old = t->d_key; + LOG (GNUNET_ERROR_TYPE_DEBUG, " new challenge for %s: %u\n", + GMT_2s (t), t->kx_ctx->challenge); + } + send_ephemeral (t); + switch (t->estate) + { + case CADET_TUNNEL3_KEY_UNINITIALIZED: + t->estate = CADET_TUNNEL3_KEY_SENT; + break; + case CADET_TUNNEL3_KEY_SENT: + break; + case CADET_TUNNEL3_KEY_PING: + case CADET_TUNNEL3_KEY_OK: + send_ping (t); + t->estate = CADET_TUNNEL3_KEY_PING; + break; + default: + LOG (GNUNET_ERROR_TYPE_DEBUG, "Unexpected state %u\n", t->estate); + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, " next call in %s\n", + GNUNET_STRINGS_relative_time_to_string (REKEY_WAIT, GNUNET_YES)); + t->rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_WAIT, &rekey_tunnel, t); +} + + +/** + * Out ephemeral key has changed, create new session key on all tunnels. + * + * @param cls Closure (size of the hashmap). + * @param key Current public key. + * @param value Value in the hash map (tunnel). + * + * @return #GNUNET_YES, so we should continue to iterate, + */ +static int +rekey_iterator (void *cls, + const struct GNUNET_PeerIdentity *key, + void *value) +{ + struct CadetTunnel3 *t = value; + struct GNUNET_TIME_Relative delay; + long n = (long) cls; + uint32_t r; + + if (GNUNET_SCHEDULER_NO_TASK != t->rekey_task) + return GNUNET_YES; + + if (GNUNET_YES == GMT_is_loopback (t)) + return GNUNET_YES; + + r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, (uint32_t) n * 100); + delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, r); + t->rekey_task = GNUNET_SCHEDULER_add_delayed (delay, &rekey_tunnel, t); + + return GNUNET_YES; +} + + +/** + * Create a new ephemeral key and key message, schedule next rekeying. + * + * @param cls Closure (unused). + * @param tc TaskContext. + */ +static void +rekey (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TIME_Absolute time; + long n; + + rekey_task = GNUNET_SCHEDULER_NO_TASK; + + if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) + return; + + GNUNET_free_non_null (my_ephemeral_key); + my_ephemeral_key = GNUNET_CRYPTO_ecdhe_key_create (); + + time = GNUNET_TIME_absolute_get (); + kx_msg.creation_time = GNUNET_TIME_absolute_hton (time); + time = GNUNET_TIME_absolute_add (time, rekey_period); + time = GNUNET_TIME_absolute_add (time, GNUNET_TIME_UNIT_MINUTES); + kx_msg.expiration_time = GNUNET_TIME_absolute_hton (time); + GNUNET_CRYPTO_ecdhe_key_get_public (my_ephemeral_key, &kx_msg.ephemeral_key); + + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign (my_private_key, + &kx_msg.purpose, + &kx_msg.signature)); + + n = (long) GNUNET_CONTAINER_multipeermap_size (tunnels); + GNUNET_CONTAINER_multipeermap_iterate (tunnels, &rekey_iterator, (void *) n); + + rekey_task = GNUNET_SCHEDULER_add_delayed (rekey_period, &rekey, NULL); +} + + +/** + * Called only on shutdown, destroy every tunnel. + * + * @param cls Closure (unused). + * @param key Current public key. + * @param value Value in the hash map (tunnel). + * + * @return #GNUNET_YES, so we should continue to iterate, + */ +static int +destroy_iterator (void *cls, + const struct GNUNET_PeerIdentity *key, + void *value) +{ + struct CadetTunnel3 *t = value; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT_shutdown destroying tunnel at %p\n", t); + GMT_destroy (t); + return GNUNET_YES; +} + + +/** + * Notify remote peer that we don't know a channel he is talking about, + * probably CHANNEL_DESTROY was missed. + * + * @param t Tunnel on which to notify. + * @param gid ID of the channel. + */ +static void +send_channel_destroy (struct CadetTunnel3 *t, unsigned int gid) +{ + struct GNUNET_CADET_ChannelManage msg; + + msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY); + msg.header.size = htons (sizeof (msg)); + msg.chid = htonl (gid); + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "WARNING destroying unknown channel %u on tunnel %s\n", + gid, GMT_2s (t)); + send_prebuilt_message (&msg.header, t, NULL, GNUNET_YES, NULL, NULL, NULL); +} + + +/** + * Demultiplex data per channel and call appropriate channel handler. + * + * @param t Tunnel on which the data came. + * @param msg Data message. + * @param fwd Is this message fwd? This only is meaningful in loopback channels. + * #GNUNET_YES if message is FWD on the respective channel (loopback) + * #GNUNET_NO if message is BCK on the respective channel (loopback) + * #GNUNET_SYSERR if message on a one-ended channel (remote) + */ +static void +handle_data (struct CadetTunnel3 *t, + const struct GNUNET_CADET_Data *msg, + int fwd) +{ + struct CadetChannel *ch; + size_t size; + + /* Check size */ + size = ntohs (msg->header.size); + if (size < + sizeof (struct GNUNET_CADET_Data) + + sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break (0); + return; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " payload of type %s\n", + GM_m2s (ntohs (msg[1].header.type))); + + /* Check channel */ + ch = GMT_get_channel (t, ntohl (msg->chid)); + if (NULL == ch) + { + GNUNET_STATISTICS_update (stats, "# data on unknown channel", + 1, GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel 0x%X unknown\n", + ntohl (msg->chid)); + send_channel_destroy (t, ntohl (msg->chid)); + return; + } + + GMCH_handle_data (ch, msg, fwd); +} + + +/** + * Demultiplex data ACKs per channel and update appropriate channel buffer info. + * + * @param t Tunnel on which the DATA ACK came. + * @param msg DATA ACK message. + * @param fwd Is this message fwd? This only is meaningful in loopback channels. + * #GNUNET_YES if message is FWD on the respective channel (loopback) + * #GNUNET_NO if message is BCK on the respective channel (loopback) + * #GNUNET_SYSERR if message on a one-ended channel (remote) + */ +static void +handle_data_ack (struct CadetTunnel3 *t, + const struct GNUNET_CADET_DataACK *msg, + int fwd) +{ + struct CadetChannel *ch; + size_t size; + + /* Check size */ + size = ntohs (msg->header.size); + if (size != sizeof (struct GNUNET_CADET_DataACK)) + { + GNUNET_break (0); + return; + } + + /* Check channel */ + ch = GMT_get_channel (t, ntohl (msg->chid)); + if (NULL == ch) + { + GNUNET_STATISTICS_update (stats, "# data ack on unknown channel", + 1, GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n", + ntohl (msg->chid)); + return; + } + + GMCH_handle_data_ack (ch, msg, fwd); +} + + +/** + * Handle channel create. + * + * @param t Tunnel on which the data came. + * @param msg Data message. + */ +static void +handle_ch_create (struct CadetTunnel3 *t, + const struct GNUNET_CADET_ChannelCreate *msg) +{ + struct CadetChannel *ch; + size_t size; + + /* Check size */ + size = ntohs (msg->header.size); + if (size != sizeof (struct GNUNET_CADET_ChannelCreate)) + { + GNUNET_break (0); + return; + } + + /* Check channel */ + ch = GMT_get_channel (t, ntohl (msg->chid)); + if (NULL != ch && ! GMT_is_loopback (t)) + { + /* Probably a retransmission, safe to ignore */ + LOG (GNUNET_ERROR_TYPE_DEBUG, " already exists...\n"); + } + ch = GMCH_handle_create (t, msg); + if (NULL != ch) + GMT_add_channel (t, ch); +} + + + +/** + * Handle channel NACK: check correctness and call channel handler for NACKs. + * + * @param t Tunnel on which the NACK came. + * @param msg NACK message. + */ +static void +handle_ch_nack (struct CadetTunnel3 *t, + const struct GNUNET_CADET_ChannelManage *msg) +{ + struct CadetChannel *ch; + size_t size; + + /* Check size */ + size = ntohs (msg->header.size); + if (size != sizeof (struct GNUNET_CADET_ChannelManage)) + { + GNUNET_break (0); + return; + } + + /* Check channel */ + ch = GMT_get_channel (t, ntohl (msg->chid)); + if (NULL == ch) + { + GNUNET_STATISTICS_update (stats, "# channel NACK on unknown channel", + 1, GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n", + ntohl (msg->chid)); + return; + } + + GMCH_handle_nack (ch); +} + + +/** + * Handle a CHANNEL ACK (SYNACK/ACK). + * + * @param t Tunnel on which the CHANNEL ACK came. + * @param msg CHANNEL ACK message. + * @param fwd Is this message fwd? This only is meaningful in loopback channels. + * #GNUNET_YES if message is FWD on the respective channel (loopback) + * #GNUNET_NO if message is BCK on the respective channel (loopback) + * #GNUNET_SYSERR if message on a one-ended channel (remote) + */ +static void +handle_ch_ack (struct CadetTunnel3 *t, + const struct GNUNET_CADET_ChannelManage *msg, + int fwd) +{ + struct CadetChannel *ch; + size_t size; + + /* Check size */ + size = ntohs (msg->header.size); + if (size != sizeof (struct GNUNET_CADET_ChannelManage)) + { + GNUNET_break (0); + return; + } + + /* Check channel */ + ch = GMT_get_channel (t, ntohl (msg->chid)); + if (NULL == ch) + { + GNUNET_STATISTICS_update (stats, "# channel ack on unknown channel", + 1, GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n", + ntohl (msg->chid)); + return; + } + + GMCH_handle_ack (ch, msg, fwd); +} + + + +/** + * Handle a channel destruction message. + * + * @param t Tunnel on which the message came. + * @param msg Channel destroy message. + * @param fwd Is this message fwd? This only is meaningful in loopback channels. + * #GNUNET_YES if message is FWD on the respective channel (loopback) + * #GNUNET_NO if message is BCK on the respective channel (loopback) + * #GNUNET_SYSERR if message on a one-ended channel (remote) + */ +static void +handle_ch_destroy (struct CadetTunnel3 *t, + const struct GNUNET_CADET_ChannelManage *msg, + int fwd) +{ + struct CadetChannel *ch; + size_t size; + + /* Check size */ + size = ntohs (msg->header.size); + if (size != sizeof (struct GNUNET_CADET_ChannelManage)) + { + GNUNET_break (0); + return; + } + + /* Check channel */ + ch = GMT_get_channel (t, ntohl (msg->chid)); + if (NULL == ch) + { + /* Probably a retransmission, safe to ignore */ + return; + } + + GMCH_handle_destroy (ch, msg, fwd); +} + + +/** + * The peer's ephemeral key has changed: update the symmetrical keys. + * + * @param t Tunnel this message came on. + * @param msg Key eXchange message. + */ +static void +handle_ephemeral (struct CadetTunnel3 *t, + const struct GNUNET_CADET_KX_Ephemeral *msg) +{ + struct GNUNET_HashCode km; + LOG (GNUNET_ERROR_TYPE_INFO, "<=== EPHM for %s\n", GMT_2s (t)); + + if (GNUNET_OK != check_ephemeral (t, msg)) + { + GNUNET_break_op (0); + return; + } + derive_key_material (&km, &msg->ephemeral_key); + LOG (GNUNET_ERROR_TYPE_DEBUG, " km is %s\n", GNUNET_h2s (&km)); + derive_symmertic (&t->e_key, &my_full_id, GMP_get_id (t->peer), &km); + derive_symmertic (&t->d_key, GMP_get_id (t->peer), &my_full_id, &km); + if (CADET_TUNNEL3_KEY_SENT == t->estate) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " our key was sent, send ping\n"); + send_ping (t); + t->estate = CADET_TUNNEL3_KEY_PING; + } +} + + +/** + * Peer wants to check our symmetrical keys by sending an encrypted challenge. + * Answer with by retransmitting the challenge with the "opposite" key. + * + * @param t Tunnel this message came on. + * @param msg Key eXchange Ping message. + */ +static void +handle_ping (struct CadetTunnel3 *t, + const struct GNUNET_CADET_KX_Ping *msg) +{ + struct GNUNET_CADET_KX_Ping res; + + if (ntohs (msg->header.size) != sizeof (res)) + { + GNUNET_break_op (0); + return; + } + + LOG (GNUNET_ERROR_TYPE_INFO, "<=== PING for %s\n", GMT_2s (t)); + t_decrypt (t, &res.target, &msg->target, ping_encryption_size (), msg->iv); + if (0 != memcmp (&my_full_id, &res.target, sizeof (my_full_id))) + { + // FIXME: move to debug + GNUNET_STATISTICS_update (stats, "# malformed PINGs", 1, GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_WARNING, " malformed PING on %s\n", GMT_2s (t)); + LOG (GNUNET_ERROR_TYPE_WARNING, " e got %u\n", msg->nonce); + LOG (GNUNET_ERROR_TYPE_WARNING, " e towards %s\n", GNUNET_i2s (&msg->target)); + LOG (GNUNET_ERROR_TYPE_WARNING, " got %u\n", res.nonce); + LOG (GNUNET_ERROR_TYPE_WARNING, " towards %s\n", GNUNET_i2s (&res.target)); + return; + } + + send_pong (t, res.nonce); +} + + +/** + * Peer has answer to our challenge. + * If answer is successful, consider the key exchange finished and clean + * up all related state. + * + * @param t Tunnel this message came on. + * @param msg Key eXchange Pong message. + */ +static void +handle_pong (struct CadetTunnel3 *t, + const struct GNUNET_CADET_KX_Pong *msg) +{ + uint32_t challenge; + + LOG (GNUNET_ERROR_TYPE_INFO, "<=== PONG for %s\n", GMT_2s (t)); + if (GNUNET_SCHEDULER_NO_TASK == t->rekey_task) + { + GNUNET_STATISTICS_update (stats, "# duplicate PONG messages", 1, GNUNET_NO); + return; + } + t_decrypt (t, &challenge, &msg->nonce, sizeof (uint32_t), msg->iv); + + if (challenge != t->kx_ctx->challenge) + { + LOG (GNUNET_ERROR_TYPE_WARNING, "Wrong PONG challenge\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, "PONG: %u (e: %u). Expected: %u.\n", + challenge, msg->nonce, t->kx_ctx->challenge); + GNUNET_break_op (0); + return; + } + GNUNET_SCHEDULER_cancel (t->rekey_task); + t->rekey_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_free (t->kx_ctx); + t->kx_ctx = NULL; + GMT_change_estate (t, CADET_TUNNEL3_KEY_OK); +} + + +/** + * Demultiplex by message type and call appropriate handler for a message + * towards a channel of a local tunnel. + * + * @param t Tunnel this message came on. + * @param msgh Message header. + * @param fwd Is this message fwd? This only is meaningful in loopback channels. + * #GNUNET_YES if message is FWD on the respective channel (loopback) + * #GNUNET_NO if message is BCK on the respective channel (loopback) + * #GNUNET_SYSERR if message on a one-ended channel (remote) + */ +static void +handle_decrypted (struct CadetTunnel3 *t, + const struct GNUNET_MessageHeader *msgh, + int fwd) +{ + uint16_t type; + + type = ntohs (msgh->type); + LOG (GNUNET_ERROR_TYPE_INFO, "<=== %s on %s\n", GM_m2s (type), GMT_2s (t)); + + switch (type) + { + case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE: + /* Do nothing, connection aleady got updated. */ + GNUNET_STATISTICS_update (stats, "# keepalives received", 1, GNUNET_NO); + break; + + case GNUNET_MESSAGE_TYPE_CADET_DATA: + /* Don't send hop ACK, wait for client to ACK */ + handle_data (t, (struct GNUNET_CADET_Data *) msgh, fwd); + break; + + case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK: + handle_data_ack (t, (struct GNUNET_CADET_DataACK *) msgh, fwd); + break; + + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE: + handle_ch_create (t, + (struct GNUNET_CADET_ChannelCreate *) msgh); + break; + + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK: + handle_ch_nack (t, + (struct GNUNET_CADET_ChannelManage *) msgh); + break; + + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK: + handle_ch_ack (t, + (struct GNUNET_CADET_ChannelManage *) msgh, + fwd); + break; + + case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: + handle_ch_destroy (t, + (struct GNUNET_CADET_ChannelManage *) msgh, + fwd); + break; + + default: + GNUNET_break_op (0); + LOG (GNUNET_ERROR_TYPE_WARNING, + "end-to-end message not known (%u)\n", + ntohs (msgh->type)); + GMT_debug (t); + } +} + +/******************************************************************************/ +/******************************** API ***********************************/ +/******************************************************************************/ + +/** + * Decrypt and demultiplex by message type. Call appropriate handler + * for every message. + * + * @param t Tunnel this message came on. + * @param msg Encrypted message. + */ +void +GMT_handle_encrypted (struct CadetTunnel3 *t, + const struct GNUNET_CADET_Encrypted *msg) +{ + size_t size = ntohs (msg->header.size); + size_t payload_size = size - sizeof (struct GNUNET_CADET_Encrypted); + size_t decrypted_size; + char cbuf [payload_size]; + struct GNUNET_MessageHeader *msgh; + unsigned int off; + struct GNUNET_CADET_Hash hmac; + + decrypted_size = t_decrypt (t, cbuf, &msg[1], payload_size, msg->iv); + t_hmac (t, &msg[1], payload_size, msg->iv, GNUNET_NO, &hmac); + if (0 != memcmp (&hmac, &msg->hmac, sizeof (hmac))) + { + /* checksum failed */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed checksum validation for a message on tunnel `%s'\n", + GMT_2s (t)); + GNUNET_STATISTICS_update (stats, "# wrong HMAC", 1, GNUNET_NO); + return; + } + off = 0; + while (off < decrypted_size) + { + msgh = (struct GNUNET_MessageHeader *) &cbuf[off]; + handle_decrypted (t, msgh, GNUNET_SYSERR); + off += ntohs (msgh->size); + } +} + + +/** + * Demultiplex an encapsulated KX message by message type. + * + * @param t Tunnel on which the message came. + * @param message Payload of KX message. + */ +void +GMT_handle_kx (struct CadetTunnel3 *t, + const struct GNUNET_MessageHeader *message) +{ + uint16_t type; + + type = ntohs (message->type); + LOG (GNUNET_ERROR_TYPE_DEBUG, "kx message received\n", type); + switch (type) + { + case GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL: + handle_ephemeral (t, (struct GNUNET_CADET_KX_Ephemeral *) message); + break; + + case GNUNET_MESSAGE_TYPE_CADET_KX_PING: + handle_ping (t, (struct GNUNET_CADET_KX_Ping *) message); + break; + + case GNUNET_MESSAGE_TYPE_CADET_KX_PONG: + handle_pong (t, (struct GNUNET_CADET_KX_Pong *) message); + break; + + default: + GNUNET_break_op (0); + LOG (GNUNET_ERROR_TYPE_DEBUG, "kx message not known (%u)\n", type); + } +} + + +/** + * Initialize the tunnel subsystem. + * + * @param c Configuration handle. + * @param key ECC private key, to derive all other keys and do crypto. + */ +void +GMT_init (const struct GNUNET_CONFIGURATION_Handle *c, + const struct GNUNET_CRYPTO_EddsaPrivateKey *key) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (c, "CADET", "DEFAULT_TTL", + &default_ttl)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, + "CADET", "DEFAULT_TTL", "USING DEFAULT"); + default_ttl = 64; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (c, "CADET", "REKEY_PERIOD", + &rekey_period)) + { + rekey_period = GNUNET_TIME_UNIT_DAYS; + } + + my_private_key = key; + kx_msg.header.size = htons (sizeof (kx_msg)); + kx_msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL); + kx_msg.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CADET_KX); + kx_msg.purpose.size = htonl (ephemeral_purpose_size ()); + kx_msg.origin_identity = my_full_id; + rekey_task = GNUNET_SCHEDULER_add_now (&rekey, NULL); + + tunnels = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES); +} + + +/** + * Shut down the tunnel subsystem. + */ +void +GMT_shutdown (void) +{ + if (GNUNET_SCHEDULER_NO_TASK != rekey_task) + { + GNUNET_SCHEDULER_cancel (rekey_task); + rekey_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_CONTAINER_multipeermap_iterate (tunnels, &destroy_iterator, NULL); + GNUNET_CONTAINER_multipeermap_destroy (tunnels); +} + + +/** + * Create a tunnel. + * + * @param destination Peer this tunnel is towards. + */ +struct CadetTunnel3 * +GMT_new (struct CadetPeer *destination) +{ + struct CadetTunnel3 *t; + + t = GNUNET_new (struct CadetTunnel3); + t->next_chid = 0; + t->peer = destination; + + if (GNUNET_OK != + GNUNET_CONTAINER_multipeermap_put (tunnels, GMP_get_id (destination), t, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) + { + GNUNET_break (0); + GNUNET_free (t); + return NULL; + } + return t; +} + + +/** + * Change the tunnel's connection state. + * + * @param t Tunnel whose connection state to change. + * @param cstate New connection state. + */ +void +GMT_change_cstate (struct CadetTunnel3* t, enum CadetTunnel3CState cstate) +{ + if (NULL == t) + return; + LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s cstate %s => %s\n", + GMP_2s (t->peer), cstate2s (t->cstate), cstate2s (cstate)); + if (myid != GMP_get_short_id (t->peer) && + CADET_TUNNEL3_READY != t->cstate && + CADET_TUNNEL3_READY == cstate) + { + t->cstate = cstate; + if (CADET_TUNNEL3_KEY_OK == t->estate) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered send queued data\n"); + send_queued_data (t); + } + else if (CADET_TUNNEL3_KEY_UNINITIALIZED == t->estate) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered rekey\n"); + rekey_tunnel (t, NULL); + } + } + t->cstate = cstate; + + if (CADET_TUNNEL3_READY == cstate + && CONNECTIONS_PER_TUNNEL <= GMT_count_connections (t)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered stop dht\n"); + GMP_stop_search (t->peer); + } +} + +/** + * Change the tunnel encryption state. + * + * @param t Tunnel whose encryption state to change. + * @param state New encryption state. + */ +void +GMT_change_estate (struct CadetTunnel3* t, enum CadetTunnel3EState state) +{ + if (NULL == t) + return; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Tunnel %s estate was %s\n", + GMP_2s (t->peer), estate2s (t->estate)); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Tunnel %s estate is now %s\n", + GMP_2s (t->peer), estate2s (state)); + if (myid != GMP_get_short_id (t->peer) && + CADET_TUNNEL3_KEY_OK != t->estate && CADET_TUNNEL3_KEY_OK == state) + { + t->estate = state; + send_queued_data (t); + return; + } + t->estate = state; +} + + +/** + * @brief Check if tunnel has too many connections, and remove one if necessary. + * + * Currently this means the newest connection, unless it is a direct one. + * Implemented as a task to avoid freeing a connection that is in the middle + * of being created/processed. + * + * @param cls Closure (Tunnel to check). + * @param tc Task context. + */ +static void +trim_connections (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CadetTunnel3 *t = cls; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + + if (GMT_count_connections (t) > 2 * CONNECTIONS_PER_TUNNEL) + { + struct CadetTConnection *iter; + struct CadetTConnection *c; + + for (c = iter = t->connection_head; NULL != iter; iter = iter->next) + { + if ((NULL == c || iter->created.abs_value_us > c->created.abs_value_us) + && GNUNET_NO == GMC_is_direct (iter->c)) + { + c = iter; + } + } + if (NULL != c) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Too many connections on tunnel %s\n", + GMT_2s (t)); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying connection %s\n", + GMC_2s (c->c)); + GMC_destroy (c->c); + } + else + { + GNUNET_break (0); + } + } +} + + +/** + * Add a connection to a tunnel. + * + * @param t Tunnel. + * @param c Connection. + */ +void +GMT_add_connection (struct CadetTunnel3 *t, struct CadetConnection *c) +{ + struct CadetTConnection *aux; + + GNUNET_assert (NULL != c); + + LOG (GNUNET_ERROR_TYPE_DEBUG, "add connection %s\n", GMC_2s (c)); + LOG (GNUNET_ERROR_TYPE_DEBUG, " to tunnel %s\n", GMT_2s (t)); + for (aux = t->connection_head; aux != NULL; aux = aux->next) + if (aux->c == c) + return; + + aux = GNUNET_new (struct CadetTConnection); + aux->c = c; + aux->created = GNUNET_TIME_absolute_get (); + + GNUNET_CONTAINER_DLL_insert (t->connection_head, t->connection_tail, aux); + + GNUNET_SCHEDULER_add_now (&trim_connections, t); +} + + +/** + * Mark a path as no longer valid for this tunnel: has been tried and failed. + * + * @param t Tunnel to update. + * @param path Invalid path to remove. Is destroyed after removal. + */ +void +GMT_remove_path (struct CadetTunnel3 *t, struct CadetPeerPath *path) +{ + GMP_remove_path (t->peer, path); +} + + +/** + * Remove a connection from a tunnel. + * + * @param t Tunnel. + * @param c Connection. + */ +void +GMT_remove_connection (struct CadetTunnel3 *t, + struct CadetConnection *c) +{ + struct CadetTConnection *aux; + struct CadetTConnection *next; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing connection %s from tunnel %s\n", + GMC_2s (c), GMT_2s (t)); + for (aux = t->connection_head; aux != NULL; aux = next) + { + next = aux->next; + if (aux->c == c) + { + GNUNET_CONTAINER_DLL_remove (t->connection_head, t->connection_tail, aux); + GNUNET_free (aux); + } + } + + /* Start new connections if needed */ + if (CONNECTIONS_PER_TUNNEL < GMT_count_connections (t) + && GNUNET_SCHEDULER_NO_TASK == t->destroy_task + && CADET_TUNNEL3_SHUTDOWN != t->cstate + && GNUNET_NO == shutting_down) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " no more connections, getting new ones\n"); + t->cstate = CADET_TUNNEL3_SEARCHING; + GMP_connect (t->peer); + return; + } + + /* If not marked as ready, no change is needed */ + if (CADET_TUNNEL3_READY != t->cstate) + return; + + /* Check if any connection is ready to maintaing cstate */ + for (aux = t->connection_head; aux != NULL; aux = aux->next) + if (CADET_CONNECTION_READY == GMC_get_state (aux->c)) + return; + + t->cstate = CADET_TUNNEL3_WAITING; +} + + +/** + * Add a channel to a tunnel. + * + * @param t Tunnel. + * @param ch Channel. + */ +void +GMT_add_channel (struct CadetTunnel3 *t, struct CadetChannel *ch) +{ + struct CadetTChannel *aux; + + GNUNET_assert (NULL != ch); + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding channel %p to tunnel %p\n", ch, t); + + for (aux = t->channel_head; aux != NULL; aux = aux->next) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " already there %p\n", aux->ch); + if (aux->ch == ch) + return; + } + + aux = GNUNET_new (struct CadetTChannel); + aux->ch = ch; + LOG (GNUNET_ERROR_TYPE_DEBUG, " adding %p to %p\n", aux, t->channel_head); + GNUNET_CONTAINER_DLL_insert_tail (t->channel_head, t->channel_tail, aux); + + if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task) + { + GNUNET_SCHEDULER_cancel (t->destroy_task); + t->destroy_task = GNUNET_SCHEDULER_NO_TASK; + LOG (GNUNET_ERROR_TYPE_DEBUG, " undo destroy!\n"); + } +} + + +/** + * Remove a channel from a tunnel. + * + * @param t Tunnel. + * @param ch Channel. + */ +void +GMT_remove_channel (struct CadetTunnel3 *t, struct CadetChannel *ch) +{ + struct CadetTChannel *aux; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing channel %p from tunnel %p\n", ch, t); + for (aux = t->channel_head; aux != NULL; aux = aux->next) + { + if (aux->ch == ch) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, " found! %s\n", GMCH_2s (ch)); + GNUNET_CONTAINER_DLL_remove (t->channel_head, t->channel_tail, aux); + GNUNET_free (aux); + return; + } + } +} + + +/** + * Search for a channel by global ID. + * + * @param t Tunnel containing the channel. + * @param chid Public channel number. + * + * @return channel handler, NULL if doesn't exist + */ +struct CadetChannel * +GMT_get_channel (struct CadetTunnel3 *t, CADET_ChannelNumber chid) +{ + struct CadetTChannel *iter; + + if (NULL == t) + return NULL; + + for (iter = t->channel_head; NULL != iter; iter = iter->next) + { + if (GMCH_get_id (iter->ch) == chid) + break; + } + + return NULL == iter ? NULL : iter->ch; +} + + +/** + * @brief Destroy a tunnel and free all resources. + * + * Should only be called a while after the tunnel has been marked as destroyed, + * in case there is a new channel added to the same peer shortly after marking + * the tunnel. This way we avoid a new public key handshake. + * + * @param cls Closure (tunnel to destroy). + * @param tc Task context. + */ +static void +delayed_destroy (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CadetTunnel3 *t = cls; + struct CadetTConnection *iter; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "delayed destroying tunnel %p\n", t); + if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + "Not destroying tunnel, due to shutdown. " + "Tunnel at %p should have been freed by GMT_shutdown\n", t); + return; + } + t->destroy_task = GNUNET_SCHEDULER_NO_TASK; + t->cstate = CADET_TUNNEL3_SHUTDOWN; + + for (iter = t->connection_head; NULL != iter; iter = iter->next) + { + GMC_send_destroy (iter->c); + } + GMT_destroy (t); +} + + +/** + * Tunnel is empty: destroy it. + * + * Notifies all connections about the destruction. + * + * @param t Tunnel to destroy. + */ +void +GMT_destroy_empty (struct CadetTunnel3 *t) +{ + if (GNUNET_YES == shutting_down) + return; /* Will be destroyed immediately anyway */ + + if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Tunnel %s is already scheduled for destruction\n", + GMT_2s (t)); + GNUNET_break (0); + /* should never happen, tunnel can only become empty once, and the + * task identifier should be NO_TASK (cleaned when the tunnel was created + * or became un-empty) + */ + return; + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s empty: destroying scheduled\n", + GMT_2s (t)); + + t->destroy_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, + &delayed_destroy, t); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduled destroy of %p as %llX\n", + t, t->destroy_task); +} + + +/** + * Destroy tunnel if empty (no more channels). + * + * @param t Tunnel to destroy if empty. + */ +void +GMT_destroy_if_empty (struct CadetTunnel3 *t) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s destroy if empty\n", GMT_2s (t)); + if (1 < GMT_count_channels (t)) + return; + + GMT_destroy_empty (t); +} + + +/** + * Destroy the tunnel. + * + * This function does not generate any warning traffic to clients or peers. + * + * Tasks: + * Cancel messages belonging to this tunnel queued to neighbors. + * Free any allocated resources linked to the tunnel. + * + * @param t The tunnel to destroy. + */ +void +GMT_destroy (struct CadetTunnel3 *t) +{ + struct CadetTConnection *iter_c; + struct CadetTConnection *next_c; + struct CadetTChannel *iter_ch; + struct CadetTChannel *next_ch; + + if (NULL == t) + return; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying tunnel %s\n", GMP_2s (t->peer)); + + GNUNET_break (GNUNET_YES == + GNUNET_CONTAINER_multipeermap_remove (tunnels, + GMP_get_id (t->peer), t)); + + for (iter_c = t->connection_head; NULL != iter_c; iter_c = next_c) + { + next_c = iter_c->next; + GMC_destroy (iter_c->c); + } + for (iter_ch = t->channel_head; NULL != iter_ch; iter_ch = next_ch) + { + next_ch = iter_ch->next; + GMCH_destroy (iter_ch->ch); + /* Should only happen on shutdown, but it's ok. */ + } + + if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "cancelling %llX\n", t->destroy_task); + GNUNET_SCHEDULER_cancel (t->destroy_task); + t->destroy_task = GNUNET_SCHEDULER_NO_TASK; + } + + GNUNET_STATISTICS_update (stats, "# tunnels", -1, GNUNET_NO); + GMP_set_tunnel (t->peer, NULL); + + if (GNUNET_SCHEDULER_NO_TASK != t->rekey_task) + { + GNUNET_SCHEDULER_cancel (t->rekey_task); + t->rekey_task = GNUNET_SCHEDULER_NO_TASK; + if (NULL != t->kx_ctx) + GNUNET_free (t->kx_ctx); + else + GNUNET_break (0); + } + + GNUNET_free (t); +} + + +/** + * @brief Use the given path for the tunnel. + * Update the next and prev hops (and RCs). + * (Re)start the path refresh in case the tunnel is locally owned. + * + * @param t Tunnel to update. + * @param p Path to use. + * + * @return Connection created. + */ +struct CadetConnection * +GMT_use_path (struct CadetTunnel3 *t, struct CadetPeerPath *p) +{ + struct CadetConnection *c; + struct GNUNET_CADET_Hash cid; + unsigned int own_pos; + + if (NULL == t || NULL == p) + { + GNUNET_break (0); + return NULL; + } + + if (CADET_TUNNEL3_SHUTDOWN == t->cstate) + { + GNUNET_break (0); + return NULL; + } + + for (own_pos = 0; own_pos < p->length; own_pos++) + { + if (p->peers[own_pos] == myid) + break; + } + if (own_pos >= p->length) + { + GNUNET_break_op (0); + return NULL; + } + + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, &cid, sizeof (cid)); + c = GMC_new (&cid, t, p, own_pos); + if (NULL == c) + { + /* Path was flawed */ + return NULL; + } + GMT_add_connection (t, c); + return c; +} + + +/** + * Count established (ready) connections of a tunnel. + * + * @param t Tunnel on which to count. + * + * @return Number of connections. + */ +unsigned int +GMT_count_connections (struct CadetTunnel3 *t) +{ + struct CadetTConnection *iter; + unsigned int count; + + if (NULL == t) + return 0; + + for (count = 0, iter = t->connection_head; NULL != iter; iter = iter->next) + if (CADET_CONNECTION_DESTROYED != GMC_get_state (iter->c)) + count++; + + return count; +} + +/** + * Count channels of a tunnel. + * + * @param t Tunnel on which to count. + * + * @return Number of channels. + */ +unsigned int +GMT_count_channels (struct CadetTunnel3 *t) +{ + struct CadetTChannel *iter; + unsigned int count; + + for (count = 0, iter = t->channel_head; + NULL != iter; + iter = iter->next, count++) /* skip */; + + return count; +} + + +/** + * Get the connectivity state of a tunnel. + * + * @param t Tunnel. + * + * @return Tunnel's connectivity state. + */ +enum CadetTunnel3CState +GMT_get_cstate (struct CadetTunnel3 *t) +{ + if (NULL == t) + { + GNUNET_assert (0); + return (enum CadetTunnel3CState) -1; + } + return t->cstate; +} + + +/** + * Get the encryption state of a tunnel. + * + * @param t Tunnel. + * + * @return Tunnel's encryption state. + */ +enum CadetTunnel3EState +GMT_get_estate (struct CadetTunnel3 *t) +{ + if (NULL == t) + { + GNUNET_assert (0); + return (enum CadetTunnel3EState) -1; + } + return t->estate; +} + +/** + * Get the maximum buffer space for a tunnel towards a local client. + * + * @param t Tunnel. + * + * @return Biggest buffer space offered by any channel in the tunnel. + */ +unsigned int +GMT_get_channels_buffer (struct CadetTunnel3 *t) +{ + struct CadetTChannel *iter; + unsigned int buffer; + unsigned int ch_buf; + + if (NULL == t->channel_head) + { + /* Probably getting buffer for a channel create/handshake. */ + return 64; + } + + buffer = 0; + for (iter = t->channel_head; NULL != iter; iter = iter->next) + { + ch_buf = get_channel_buffer (iter); + if (ch_buf > buffer) + buffer = ch_buf; + } + return buffer; +} + + +/** + * Get the total buffer space for a tunnel for P2P traffic. + * + * @param t Tunnel. + * + * @return Buffer space offered by all connections in the tunnel. + */ +unsigned int +GMT_get_connections_buffer (struct CadetTunnel3 *t) +{ + struct CadetTConnection *iter; + unsigned int buffer; + + buffer = 0; + for (iter = t->connection_head; NULL != iter; iter = iter->next) + { + if (GMC_get_state (iter->c) != CADET_CONNECTION_READY) + { + continue; + } + buffer += get_connection_buffer (iter); + } + + return buffer; +} + + +/** + * Get the tunnel's destination. + * + * @param t Tunnel. + * + * @return ID of the destination peer. + */ +const struct GNUNET_PeerIdentity * +GMT_get_destination (struct CadetTunnel3 *t) +{ + return GMP_get_id (t->peer); +} + + +/** + * Get the tunnel's next free global channel ID. + * + * @param t Tunnel. + * + * @return GID of a channel free to use. + */ +CADET_ChannelNumber +GMT_get_next_chid (struct CadetTunnel3 *t) +{ + CADET_ChannelNumber chid; + CADET_ChannelNumber mask; + int result; + + /* Set bit 30 depending on the ID relationship. Bit 31 is always 0 for GID. + * If our ID is bigger or loopback tunnel, start at 0, bit 30 = 0 + * If peer's ID is bigger, start at 0x4... bit 30 = 1 + */ + result = GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, GMP_get_id (t->peer)); + if (0 > result) + mask = 0x40000000; + else + mask = 0x0; + t->next_chid |= mask; + + while (NULL != GMT_get_channel (t, t->next_chid)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %u exists...\n", t->next_chid); + t->next_chid = (t->next_chid + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI; + t->next_chid |= mask; + } + chid = t->next_chid; + t->next_chid = (t->next_chid + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI; + t->next_chid |= mask; + + return chid; +} + + +/** + * Send ACK on one or more channels due to buffer in connections. + * + * @param t Channel which has some free buffer space. + */ +void +GMT_unchoke_channels (struct CadetTunnel3 *t) +{ + struct CadetTChannel *iter; + unsigned int buffer; + unsigned int channels = GMT_count_channels (t); + unsigned int choked_n; + struct CadetChannel *choked[channels]; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT_unchoke_channels on %s\n", GMT_2s (t)); + LOG (GNUNET_ERROR_TYPE_DEBUG, " head: %p\n", t->channel_head); + if (NULL != t->channel_head) + LOG (GNUNET_ERROR_TYPE_DEBUG, " head ch: %p\n", t->channel_head->ch); + + /* Get buffer space */ + buffer = GMT_get_connections_buffer (t); + if (0 == buffer) + { + return; + } + + /* Count and remember choked channels */ + choked_n = 0; + for (iter = t->channel_head; NULL != iter; iter = iter->next) + { + if (GNUNET_NO == get_channel_allowed (iter)) + { + choked[choked_n++] = iter->ch; + } + } + + /* Unchoke random channels */ + while (0 < buffer && 0 < choked_n) + { + unsigned int r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + choked_n); + GMCH_allow_client (choked[r], GMCH_is_origin (choked[r], GNUNET_YES)); + choked_n--; + buffer--; + choked[r] = choked[choked_n]; + } +} + + +/** + * Send ACK on one or more connections due to buffer space to the client. + * + * Iterates all connections of the tunnel and sends ACKs appropriately. + * + * @param t Tunnel. + */ +void +GMT_send_connection_acks (struct CadetTunnel3 *t) +{ + struct CadetTConnection *iter; + uint32_t allowed; + uint32_t to_allow; + uint32_t allow_per_connection; + unsigned int cs; + unsigned int buffer; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel send connection ACKs on %s\n", + GMT_2s (t)); + + if (NULL == t) + { + GNUNET_break (0); + return; + } + + buffer = GMT_get_channels_buffer (t); + LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer %u\n", buffer); + + /* Count connections, how many messages are already allowed */ + cs = GMT_count_connections (t); + for (allowed = 0, iter = t->connection_head; NULL != iter; iter = iter->next) + { + allowed += get_connection_allowed (iter); + } + LOG (GNUNET_ERROR_TYPE_DEBUG, " allowed %u\n", allowed); + + /* Make sure there is no overflow */ + if (allowed > buffer) + { + return; + } + + /* Authorize connections to send more data */ + to_allow = buffer; /* - allowed; */ + + for (iter = t->connection_head; + NULL != iter && to_allow > 0; + iter = iter->next) + { + allow_per_connection = to_allow/cs; + to_allow -= allow_per_connection; + cs--; + if (get_connection_allowed (iter) > 64 / 3) + { + continue; + } + GMC_allow (iter->c, allow_per_connection, + GMC_is_origin (iter->c, GNUNET_NO)); + } + + GNUNET_break (to_allow == 0); +} + + +/** + * Cancel a previously sent message while it's in the queue. + * + * ONLY can be called before the continuation given to the send function + * is called. Once the continuation is called, the message is no longer in the + * queue. + * + * @param q Handle to the queue. + */ +void +GMT_cancel (struct CadetTunnel3Queue *q) +{ + if (NULL != q->cq) + { + GMC_cancel (q->cq); + /* tun_message_sent() will be called and free q */ + } + else if (NULL != q->tqd) + { + unqueue_data (q->tqd); + q->tqd = NULL; + if (NULL != q->cont) + q->cont (q->cont_cls, NULL, q, 0, 0); + GNUNET_free (q); + } + else + { + GNUNET_break (0); + } +} + + +/** + * Sends an already built message on a tunnel, encrypting it and + * choosing the best connection if not provided. + * + * @param message Message to send. Function modifies it. + * @param t Tunnel on which this message is transmitted. + * @param c Connection to use (autoselect if NULL). + * @param force Force the tunnel to take the message (buffer overfill). + * @param cont Continuation to call once message is really sent. + * @param cont_cls Closure for @c cont. + * + * @return Handle to cancel message. NULL if @c cont is NULL. + */ +struct CadetTunnel3Queue * +GMT_send_prebuilt_message (const struct GNUNET_MessageHeader *message, + struct CadetTunnel3 *t, struct CadetConnection *c, + int force, GMT_sent cont, void *cont_cls) +{ + return send_prebuilt_message (message, t, c, force, cont, cont_cls, NULL); +} + + +/** + * Is the tunnel directed towards the local peer? + * + * @param t Tunnel. + * + * @return #GNUNET_YES if it is loopback. + */ +int +GMT_is_loopback (const struct CadetTunnel3 *t) +{ + return (myid == GMP_get_short_id (t->peer)); +} + + +/** + * Is the tunnel this path already? + * + * @param t Tunnel. + * @param p Path. + * + * @return #GNUNET_YES a connection uses this path. + */ +int +GMT_is_path_used (const struct CadetTunnel3 *t, const struct CadetPeerPath *p) +{ + struct CadetTConnection *iter; + + for (iter = t->connection_head; NULL != iter; iter = iter->next) + if (GMC_get_path (iter->c) == p) + return GNUNET_YES; + + return GNUNET_NO; +} + + +/** + * Get a cost of a path for a tunnel considering existing connections. + * + * @param t Tunnel. + * @param path Candidate path. + * + * @return Cost of the path (path length + number of overlapping nodes) + */ +unsigned int +GMT_get_path_cost (const struct CadetTunnel3 *t, + const struct CadetPeerPath *path) +{ + struct CadetTConnection *iter; + const struct CadetPeerPath *aux; + unsigned int overlap; + unsigned int i; + unsigned int j; + + if (NULL == path) + return 0; + + overlap = 0; + GNUNET_assert (NULL != t); + + for (i = 0; i < path->length; i++) + { + for (iter = t->connection_head; NULL != iter; iter = iter->next) + { + aux = GMC_get_path (iter->c); + if (NULL == aux) + continue; + + for (j = 0; j < aux->length; j++) + { + if (path->peers[i] == aux->peers[j]) + { + overlap++; + break; + } + } + } + } + return path->length + overlap; +} + + +/** + * Get the static string for the peer this tunnel is directed. + * + * @param t Tunnel. + * + * @return Static string the destination peer's ID. + */ +const char * +GMT_2s (const struct CadetTunnel3 *t) +{ + if (NULL == t) + return "(NULL)"; + + return GMP_2s (t->peer); +} + + +/******************************************************************************/ +/***************************** INFO/DEBUG *******************************/ +/******************************************************************************/ + + +/** + * Log all possible info about the tunnel state to stderr. + * + * @param t Tunnel to debug. + */ +void +GMT_debug (const struct CadetTunnel3 *t) +{ + struct CadetTChannel *iterch; + struct CadetTConnection *iterc; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT DEBUG TUNNEL TOWARDS %s\n", GMT_2s (t)); + LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT cstate %s, estate %s\n", + cstate2s (t->cstate), estate2s (t->estate)); + LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT kx_ctx %p, rekey_task %u\n", + t->kx_ctx, t->rekey_task); + LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT tq_head %p, tq_tail %p\n", + t->tq_head, t->tq_tail); + LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT destroy %u\n", t->destroy_task); + + LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT channels:\n"); + for (iterch = t->channel_head; NULL != iterch; iterch = iterch->next) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT - %s\n", GMCH_2s (iterch->ch)); + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT connections:\n"); + for (iterc = t->connection_head; NULL != iterc; iterc = iterc->next) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT - %s [%u] buf: %u/%u (qn %u/%u)\n", + GMC_2s (iterc->c), GMC_get_state (iterc->c), + GMC_get_buffer (iterc->c, GNUNET_YES), + GMC_get_buffer (iterc->c, GNUNET_NO), + GMC_get_qn (iterc->c, GNUNET_YES), + GMC_get_qn (iterc->c, GNUNET_NO)); + } + + LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT DEBUG TUNNEL END\n"); +} + + +/** + * Iterate all tunnels. + * + * @param iter Iterator. + * @param cls Closure for @c iter. + */ +void +GMT_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls) +{ + GNUNET_CONTAINER_multipeermap_iterate (tunnels, iter, cls); +} + + +/** + * Count all tunnels. + * + * @return Number of tunnels to remote peers kept by this peer. + */ +unsigned int +GMT_count_all (void) +{ + return GNUNET_CONTAINER_multipeermap_size (tunnels); +} + + +/** + * Iterate all connections of a tunnel. + * + * @param t Tunnel whose connections to iterate. + * @param iter Iterator. + * @param cls Closure for @c iter. + */ +void +GMT_iterate_connections (struct CadetTunnel3 *t, GMT_conn_iter iter, void *cls) +{ + struct CadetTConnection *ct; + + for (ct = t->connection_head; NULL != ct; ct = ct->next) + iter (cls, ct->c); +} + + +/** + * Iterate all channels of a tunnel. + * + * @param t Tunnel whose channels to iterate. + * @param iter Iterator. + * @param cls Closure for @c iter. + */ +void +GMT_iterate_channels (struct CadetTunnel3 *t, GMT_chan_iter iter, void *cls) +{ + struct CadetTChannel *cht; + + for (cht = t->channel_head; NULL != cht; cht = cht->next) + iter (cls, cht->ch); +} diff --git a/src/cadet/gnunet-service-cadet_tunnel.h b/src/cadet/gnunet-service-cadet_tunnel.h new file mode 100644 index 000000000..16616de59 --- /dev/null +++ b/src/cadet/gnunet-service-cadet_tunnel.h @@ -0,0 +1,531 @@ +/* + This file is part of GNUnet. + (C) 2013 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 cadet/gnunet-service-cadet_tunnel.h + * @brief cadet service; dealing with tunnels and crypto + * @author Bartlomiej Polot + * + * All functions in this file should use the prefix GMT (Gnunet Cadet Tunnel) + */ + +#ifndef GNUNET_SERVICE_CADET_TUNNEL_H +#define GNUNET_SERVICE_CADET_TUNNEL_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "platform.h" +#include "gnunet_util_lib.h" + +/** + * All the connectivity states a tunnel can be in. + */ +enum CadetTunnel3CState +{ + /** + * Uninitialized status, should never appear in operation. + */ + CADET_TUNNEL3_NEW, + + /** + * Path to the peer not known yet. + */ + CADET_TUNNEL3_SEARCHING, + + /** + * Request sent, not yet answered. + */ + CADET_TUNNEL3_WAITING, + + /** + * Peer connected and ready to accept data. + */ + CADET_TUNNEL3_READY, + + /** + * Tunnel being shut down, don't try to keep it alive. + */ + CADET_TUNNEL3_SHUTDOWN +}; + + +/** + * All the encryption states a tunnel can be in. + */ +enum CadetTunnel3EState +{ + /** + * Uninitialized status, should never appear in operation. + */ + CADET_TUNNEL3_KEY_UNINITIALIZED, + + /** + * Ephemeral key sent, waiting for peer's key. + */ + CADET_TUNNEL3_KEY_SENT, + + /** + * New ephemeral key and ping sent, waiting for pong. + * This means that we DO have the peer's ephemeral key, otherwise the + * state would be KEY_SENT. + */ + CADET_TUNNEL3_KEY_PING, + + /** + * Handshake completed: session key available. + */ + CADET_TUNNEL3_KEY_OK, +}; + +/** + * Struct containing all information regarding a given peer + */ +struct CadetTunnel3; + + +#include "gnunet-service-cadet_channel.h" +#include "gnunet-service-cadet_connection.h" +#include "gnunet-service-cadet_peer.h" + +/** + * Handle for messages queued but not yet sent. + */ +struct CadetTunnel3Queue; + +/** + * Callback called when a queued message is sent. + * + * @param cls Closure. + * @param t Tunnel this message was on. + * @param type Type of message sent. + * @param size Size of the message. + */ +typedef void (*GMT_sent) (void *cls, + struct CadetTunnel3 *t, + struct CadetTunnel3Queue *q, + uint16_t type, size_t size); + +typedef void (*GMT_conn_iter) (void *cls, struct CadetConnection *c); +typedef void (*GMT_chan_iter) (void *cls, struct CadetChannel *ch); + + +/******************************************************************************/ +/******************************** API ***********************************/ +/******************************************************************************/ + +/** + * Initialize tunnel subsystem. + * + * @param c Configuration handle. + * @param key ECC private key, to derive all other keys and do crypto. + */ +void +GMT_init (const struct GNUNET_CONFIGURATION_Handle *c, + const struct GNUNET_CRYPTO_EddsaPrivateKey *key); + +/** + * Shut down the tunnel subsystem. + */ +void +GMT_shutdown (void); + +/** + * Create a tunnel. + * + * @param destination Peer this tunnel is towards. + */ +struct CadetTunnel3 * +GMT_new (struct CadetPeer *destination); + +/** + * Tunnel is empty: destroy it. + * + * Notifies all connections about the destruction. + * + * @param t Tunnel to destroy. + */ +void +GMT_destroy_empty (struct CadetTunnel3 *t); + +/** + * Destroy tunnel if empty (no more channels). + * + * @param t Tunnel to destroy if empty. + */ +void +GMT_destroy_if_empty (struct CadetTunnel3 *t); + +/** + * Destroy the tunnel. + * + * This function does not generate any warning traffic to clients or peers. + * + * Tasks: + * Cancel messages belonging to this tunnel queued to neighbors. + * Free any allocated resources linked to the tunnel. + * + * @param t The tunnel to destroy. + */ +void +GMT_destroy (struct CadetTunnel3 *t); + + +/** + * Change the tunnel's connection state. + * + * @param t Tunnel whose connection state to change. + * @param cstate New connection state. + */ +void +GMT_change_cstate (struct CadetTunnel3* t, enum CadetTunnel3CState cstate); + + +/** + * Change the tunnel encryption state. + * + * @param t Tunnel whose encryption state to change. + * @param state New encryption state. + */ +void +GMT_change_estate (struct CadetTunnel3* t, enum CadetTunnel3EState state); + +/** + * Add a connection to a tunnel. + * + * @param t Tunnel. + * @param c Connection. + */ +void +GMT_add_connection (struct CadetTunnel3 *t, struct CadetConnection *c); + +/** + * Mark a path as no longer valid for this tunnel: has been tried and failed. + * + * @param t Tunnel to update. + * @param path Invalid path to remove. Is destroyed after removal. + */ +void +GMT_remove_path (struct CadetTunnel3 *t, struct CadetPeerPath *path); + +/** + * Remove a connection from a tunnel. + * + * @param t Tunnel. + * @param c Connection. + */ +void +GMT_remove_connection (struct CadetTunnel3 *t, struct CadetConnection *c); + +/** + * Add a channel to a tunnel. + * + * @param t Tunnel. + * @param ch Channel. + */ +void +GMT_add_channel (struct CadetTunnel3 *t, struct CadetChannel *ch); + +/** + * Remove a channel from a tunnel. + * + * @param t Tunnel. + * @param ch Channel. + */ +void +GMT_remove_channel (struct CadetTunnel3 *t, struct CadetChannel *ch); + +/** + * Search for a channel by global ID. + * + * @param t Tunnel containing the channel. + * @param chid Public channel number. + * + * @return channel handler, NULL if doesn't exist + */ +struct CadetChannel * +GMT_get_channel (struct CadetTunnel3 *t, CADET_ChannelNumber chid); + +/** + * Decrypt and demultiplex by message type. Call appropriate handler + * for a message + * towards a channel of a local tunnel. + * + * @param t Tunnel this message came on. + * @param msg Message header. + */ +void +GMT_handle_encrypted (struct CadetTunnel3 *t, + const struct GNUNET_CADET_Encrypted *msg); + +/** + * Demultiplex an encapsulated KX message by message type. + * + * @param t Tunnel on which the message came. + * @param message KX message itself. + */ +void +GMT_handle_kx (struct CadetTunnel3 *t, + const struct GNUNET_MessageHeader *message); + +/** + * @brief Use the given path for the tunnel. + * Update the next and prev hops (and RCs). + * (Re)start the path refresh in case the tunnel is locally owned. + * + * @param t Tunnel to update. + * @param p Path to use. + * + * @return Connection created. + */ +struct CadetConnection * +GMT_use_path (struct CadetTunnel3 *t, struct CadetPeerPath *p); + +/** + * Count established (ready) connections of a tunnel. + * + * @param t Tunnel on which to count. + * + * @return Number of connections. + */ +unsigned int +GMT_count_connections (struct CadetTunnel3 *t); + +/** + * Count channels of a tunnel. + * + * @param t Tunnel on which to count. + * + * @return Number of channels. + */ +unsigned int +GMT_count_channels (struct CadetTunnel3 *t); + +/** + * Get the connectivity state of a tunnel. + * + * @param t Tunnel. + * + * @return Tunnel's connectivity state. + */ +enum CadetTunnel3CState +GMT_get_cstate (struct CadetTunnel3 *t); + +/** + * Get the encryption state of a tunnel. + * + * @param t Tunnel. + * + * @return Tunnel's encryption state. + */ +enum CadetTunnel3EState +GMT_get_estate (struct CadetTunnel3 *t); + +/** + * Get the maximum buffer space for a tunnel towards a local client. + * + * @param t Tunnel. + * + * @return Biggest buffer space offered by any channel in the tunnel. + */ +unsigned int +GMT_get_channels_buffer (struct CadetTunnel3 *t); + +/** + * Get the total buffer space for a tunnel for P2P traffic. + * + * @param t Tunnel. + * + * @return Buffer space offered by all connections in the tunnel. + */ +unsigned int +GMT_get_connections_buffer (struct CadetTunnel3 *t); + +/** + * Get the tunnel's destination. + * + * @param t Tunnel. + * + * @return ID of the destination peer. + */ +const struct GNUNET_PeerIdentity * +GMT_get_destination (struct CadetTunnel3 *t); + +/** + * Get the tunnel's next free Channel ID. + * + * @param t Tunnel. + * + * @return ID of a channel free to use. + */ +CADET_ChannelNumber +GMT_get_next_chid (struct CadetTunnel3 *t); + +/** + * Send ACK on one or more channels due to buffer in connections. + * + * @param t Channel which has some free buffer space. + */ +void +GMT_unchoke_channels (struct CadetTunnel3 *t); + +/** + * Send ACK on one or more connections due to buffer space to the client. + * + * Iterates all connections of the tunnel and sends ACKs appropriately. + * + * @param t Tunnel which has some free buffer space. + */ +void +GMT_send_connection_acks (struct CadetTunnel3 *t); + +/** + * Cancel a previously sent message while it's in the queue. + * + * ONLY can be called before the continuation given to the send function + * is called. Once the continuation is called, the message is no longer in the + * queue. + * + * @param q Handle to the queue. + */ +void +GMT_cancel (struct CadetTunnel3Queue *q); + +/** + * Sends an already built message on a tunnel, encrypting it and + * choosing the best connection. + * + * @param message Message to send. Function modifies it. + * @param t Tunnel on which this message is transmitted. + * @param c Connection to use (autoselect if NULL). + * @param force Force the tunnel to take the message (buffer overfill). + * @param cont Continuation to call once message is really sent. + * @param cont_cls Closure for @c cont. + * + * @return Handle to cancel message. NULL if @c cont is NULL. + */ +struct CadetTunnel3Queue * +GMT_send_prebuilt_message (const struct GNUNET_MessageHeader *message, + struct CadetTunnel3 *t, struct CadetConnection *c, + int force, GMT_sent cont, void *cont_cls); + +/** + * Is the tunnel directed towards the local peer? + * + * @param t Tunnel. + * + * @return #GNUNET_YES if it is loopback. + */ +int +GMT_is_loopback (const struct CadetTunnel3 *t); + +/** + * Is the tunnel using this path already? + * + * @param t Tunnel. + * @param p Path. + * + * @return #GNUNET_YES a connection uses this path. + */ +int +GMT_is_path_used (const struct CadetTunnel3 *t, const struct CadetPeerPath *p); + +/** + * Get a cost of a path for a tunnel considering existing connections. + * + * @param t Tunnel. + * @param path Candidate path. + * + * @return Cost of the path (path length + number of overlapping nodes) + */ +unsigned int +GMT_get_path_cost (const struct CadetTunnel3 *t, + const struct CadetPeerPath *path); + +/** + * Get the static string for the peer this tunnel is directed. + * + * @param t Tunnel. + * + * @return Static string the destination peer's ID. + */ +const char * +GMT_2s (const struct CadetTunnel3 *t); + +/** + * Log all possible info about the tunnel state. + * + * @param t Tunnel to debug. + */ +void +GMT_debug (const struct CadetTunnel3 *t); + +/** + * Iterate all tunnels. + * + * @param iter Iterator. + * @param cls Closure for @c iter. + */ +void +GMT_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls); + +/** + * Count all tunnels. + * + * @return Number of tunnels to remote peers kept by this peer. + */ +unsigned int +GMT_count_all (void); + +/** + * Iterate all connections of a tunnel. + * + * @param t Tunnel whose connections to iterate. + * @param iter Iterator. + * @param cls Closure for @c iter. + */ +void +GMT_iterate_connections (struct CadetTunnel3 *t, GMT_conn_iter iter, void *cls); + +/** + * Iterate all channels of a tunnel. + * + * @param t Tunnel whose channels to iterate. + * @param iter Iterator. + * @param cls Closure for @c iter. + */ +void +GMT_iterate_channels (struct CadetTunnel3 *t, GMT_chan_iter iter, void *cls); + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_CADET_SERVICE_TUNNEL_H */ +#endif +/* end of gnunet-cadet-service_tunnel.h */ diff --git a/src/cadet/loopcheck.sh b/src/cadet/loopcheck.sh new file mode 100755 index 000000000..2ea737ecb --- /dev/null +++ b/src/cadet/loopcheck.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +while true; do + date; + taskset 1 make check || break; + grep -B 10 Assert *log && break + ls core* &> /dev/null && break +done diff --git a/src/cadet/mesh.conf.in b/src/cadet/mesh.conf.in new file mode 100644 index 000000000..c6bb09dd7 --- /dev/null +++ b/src/cadet/mesh.conf.in @@ -0,0 +1,21 @@ +[mesh] +AUTOSTART = @AUTOSTART@ +@JAVAPORT@PORT = 2096 +HOSTNAME = localhost +BINARY = gnunet-service-mesh +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-mesh.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +REFRESH_CONNECTION_TIME = 5 min +ID_ANNOUNCE_TIME = 1 h +APP_ANNOUNCE_TIME = 1 h +CONNECT_TIMEOUT = 30 s +DEFAULT_TTL = 64 +DHT_REPLICATION_LEVEL = 3 +MAX_TUNNELS = 1000 +# MAX_TUNNELS deprecated +MAX_CONNECTIONS = 1000 +MAX_MSGS_QUEUE = 10000 +MAX_PEERS = 1000 diff --git a/src/cadet/profiler.conf b/src/cadet/profiler.conf new file mode 100644 index 000000000..8817802d1 --- /dev/null +++ b/src/cadet/profiler.conf @@ -0,0 +1,19 @@ +@INLINE@ test_mesh.conf + +[testbed] +OVERLAY_TOPOLOGY = RANDOM +OVERLAY_RANDOM_LINKS = %LINKS% +MAX_PARALLEL_SERVICE_CONNECTIONS=4000 +SETUP_TIMEOUT = 60 m + +[transport] +#MANIPULATE_DELAY_IN = 50 ms +MANIPULATE_DELAY_OUT = 10 ms + +[mesh] +REFRESH_CONNECTION_TIME = 1 h +DISABLE_TRY_CONNECT = YES +ID_ANNOUNCE_TIME = 240 s + +[dht] +FORCE_NSE = %NSE% diff --git a/src/cadet/run_profiler.sh b/src/cadet/run_profiler.sh new file mode 100755 index 000000000..aba6ce4d4 --- /dev/null +++ b/src/cadet/run_profiler.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +if [ "$#" -lt "3" ]; then + echo "usage: $0 ROUND_TIME PEERS PINGING_PEERS"; + echo "example: $0 30s 16 1"; + exit 1; +fi + +ROUNDTIME=$1 +PEERS=$2 +PINGS=$3 + +if [ $PEERS -eq 1 ]; then + echo "cannot run 1 peer"; + exit 1; +fi + +LINKS=`echo "l($PEERS)/l(2) * $PEERS" | bc -l` +LINKS=`printf "%.0f" $LINKS` +NSE=`echo "l($PEERS)/l(2)" | bc -l` +echo "using $PEERS peers, $LINKS links"; + +sed -e "s/%LINKS%/$LINKS/;s/%NSE%/$NSE/" profiler.conf > .profiler.conf + +./gnunet-mesh-profiler $ROUNDTIME $PEERS $PINGS $4 |& tee log | grep -v DEBUG diff --git a/src/cadet/small.dat b/src/cadet/small.dat new file mode 100644 index 000000000..c3805ee80 --- /dev/null +++ b/src/cadet/small.dat @@ -0,0 +1,21 @@ +16 +1:2 +1:9 +2:3 +3:4 +3:11 +4:5 +5:6 +5:13 +6:7 +7:8 +7:15 +8:9 +9:10 +10:11 +11:12 +12:13 +13:14 +14:15 +15:16 +16:1 diff --git a/src/cadet/test_cadet.c b/src/cadet/test_cadet.c new file mode 100644 index 000000000..ac2661a86 --- /dev/null +++ b/src/cadet/test_cadet.c @@ -0,0 +1,953 @@ +/* + 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 cadet/test_cadet.c + * + * @brief Test for the cadet service: retransmission of traffic. + */ +#include +#include "platform.h" +#include "cadet_test_lib.h" +#include "gnunet_cadet_service.h" +#include "gnunet_statistics_service.h" +#include + + +/** + * How namy messages to send + */ +#define TOTAL_PACKETS 100 + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) + +/** + * Time to wait for stuff that should be rather fast + */ +#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) + +/** + * DIFFERENT TESTS TO RUN + */ +#define SETUP 0 +#define FORWARD 1 +#define KEEPALIVE 2 +#define SPEED 3 +#define SPEED_ACK 4 +#define SPEED_REL 8 +#define P2P_SIGNAL 10 + +/** + * Which test are we running? + */ +static int test; + +/** + * String with test name + */ +char *test_name; + +/** + * Flag to send traffic leaf->root in speed tests to test BCK_ACK logic. + */ +static int test_backwards = GNUNET_NO; + +/** + * How many events have happened + */ +static int ok; + +/** + * Number of events expected to conclude the test successfully. + */ +int ok_goal; + +/** + * Size of each test packet + */ +size_t size_payload = sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t); + +/** + * Operation to get peer ids. + */ +struct GNUNET_TESTBED_Operation *t_op[2]; + +/** + * Peer ids. + */ +struct GNUNET_PeerIdentity *p_id[2]; + +/** + * Peer ids counter. + */ +unsigned int p_ids; + +/** + * Is the setup initialized? + */ +static int initialized; + +/** + * Number of payload packes sent + */ +static int data_sent; + +/** + * Number of payload packets received + */ +static int data_received; + +/** + * Number of payload packed explicitly (app level) acknowledged + */ +static int data_ack; + +/** + * Total number of currently running peers. + */ +static unsigned long long peers_running; + +/** + * Test context (to shut down). + */ +struct GNUNET_CADET_TEST_Context *test_ctx; + +/** + * Task called to disconnect peers. + */ +static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; + +/** + * Task To perform tests + */ +static GNUNET_SCHEDULER_TaskIdentifier test_task; + +/** + * Task called to shutdown test. + */ +static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; + +/** + * Cadet handle for the root peer + */ +static struct GNUNET_CADET_Handle *h1; + +/** + * Cadet handle for the first leaf peer + */ +static struct GNUNET_CADET_Handle *h2; + +/** + * Channel handle for the root peer + */ +static struct GNUNET_CADET_Channel *ch; + +/** + * Channel handle for the dest peer + */ +static struct GNUNET_CADET_Channel *incoming_ch; + +/** + * Time we started the data transmission (after channel has been established + * and initilized). + */ +static struct GNUNET_TIME_Absolute start_time; + +/** + * Peers handle. + */ +static struct GNUNET_TESTBED_Peer **testbed_peers; + +/** + * Statistics operation handle. + */ +static struct GNUNET_TESTBED_Operation *stats_op; + +/** + * Keepalives sent. + */ +static unsigned int ka_sent; + +/** + * Keepalives received. + */ +static unsigned int ka_received; + + +/** + * Show the results of the test (banwidth acheived) and log them to GAUGER + */ +static void +show_end_data (void) +{ + static struct GNUNET_TIME_Absolute end_time; + static struct GNUNET_TIME_Relative total_time; + + end_time = GNUNET_TIME_absolute_get(); + total_time = GNUNET_TIME_absolute_get_difference(start_time, end_time); + FPRINTF (stderr, "\nResults of test \"%s\"\n", test_name); + FPRINTF (stderr, "Test time %s\n", + GNUNET_STRINGS_relative_time_to_string (total_time, + GNUNET_YES)); + FPRINTF (stderr, "Test bandwidth: %f kb/s\n", + 4 * TOTAL_PACKETS * 1.0 / (total_time.rel_value_us / 1000)); // 4bytes * ms + FPRINTF (stderr, "Test throughput: %f packets/s\n\n", + TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000)); // packets * ms + GAUGER ("CADET", test_name, + TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000), + "packets/s"); +} + + +/** + * Shut down peergroup, clean up. + * + * @param cls Closure (unused). + * @param tc Task Context. + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n"); + shutdown_handle = GNUNET_SCHEDULER_NO_TASK; +} + + +/** + * Disconnect from cadet services af all peers, call shutdown. + * + * @param cls Closure (unused). + * @param tc Task Context. + */ +static void +disconnect_cadet_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + long line = (long) cls; + unsigned int i; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "disconnecting cadet service of peers, called from line %ld\n", + line); + disconnect_task = GNUNET_SCHEDULER_NO_TASK; + for (i = 0; i < 2; i++) + { + GNUNET_TESTBED_operation_done (t_op[i]); + } + if (NULL != ch) + { + GNUNET_CADET_channel_destroy (ch); + ch = NULL; + } + if (NULL != incoming_ch) + { + GNUNET_CADET_channel_destroy (incoming_ch); + incoming_ch = NULL; + } + GNUNET_CADET_TEST_cleanup (test_ctx); + if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle) + { + GNUNET_SCHEDULER_cancel (shutdown_handle); + } + shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); +} + + +/** + * Abort test: schedule disconnect and shutdown immediately + * + * @param line Line in the code the abort is requested from (__LINE__). + */ +static void +abort_test (long line) +{ + if (disconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, + (void *) line); + } +} + +/** + * Transmit ready callback. + * + * @param cls Closure (message type). + * @param size Size of the tranmist buffer. + * @param buf Pointer to the beginning of the buffer. + * + * @return Number of bytes written to buf. + */ +static size_t +tmt_rdy (void *cls, size_t size, void *buf); + + +/** + * Task to schedule a new data transmission. + * + * @param cls Closure (peer #). + * @param tc Task Context. + */ +static void +data_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_CADET_TransmitHandle *th; + struct GNUNET_CADET_Channel *channel; + + if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0) + return; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data task\n"); + if (GNUNET_YES == test_backwards) + { + channel = incoming_ch; + } + else + { + channel = ch; + } + th = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO, + GNUNET_TIME_UNIT_FOREVER_REL, + size_payload, &tmt_rdy, (void *) 1L); + if (NULL == th) + { + unsigned long i = (unsigned long) cls; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Retransmission\n"); + if (0 == i) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, " in 1 ms\n"); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, + &data_task, (void *)1UL); + } + else + { + i++; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "in %u ms\n", i); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply( + GNUNET_TIME_UNIT_MILLISECONDS, + i), + &data_task, (void *)i); + } + } +} + + +/** + * Transmit ready callback + * + * @param cls Closure (message type). + * @param size Size of the buffer we have. + * @param buf Buffer to copy data to. + */ +size_t +tmt_rdy (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader *msg = buf; + uint32_t *data; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "tmt_rdy called, filling buffer\n"); + if (size < size_payload || NULL == buf) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "size %u, buf %p, data_sent %u, data_received %u\n", + size, buf, data_sent, data_received); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ok %u, ok goal %u\n", ok, ok_goal); + GNUNET_break (ok >= ok_goal - 2); + + return 0; + } + msg->size = htons (size); + msg->type = htons ((long) cls); + data = (uint32_t *) &msg[1]; + *data = htonl (data_sent); + if (GNUNET_NO == initialized) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "sending initializer\n"); + } + else if (SPEED == test) + { + data_sent++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " Sent packet %d\n", data_sent); + if (data_sent < TOTAL_PACKETS) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " Scheduling packet %d\n", data_sent + 1); + GNUNET_SCHEDULER_add_now (&data_task, NULL); + } + } + + return size_payload; +} + + +/** + * Function is called whenever a message is received. + * + * @param cls closure (set from GNUNET_CADET_connect) + * @param channel connection to the other end + * @param channel_ctx place to store local state associated with the channel + * @param message the actual message + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +int +data_callback (void *cls, struct GNUNET_CADET_Channel *channel, + void **channel_ctx, + const struct GNUNET_MessageHeader *message) +{ + long client = (long) cls; + long expected_target_client; + uint32_t *data; + + ok++; + + GNUNET_CADET_receive_done (channel); + + if ((ok % 20) == 0) + { + if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, + &disconnect_cadet_peers, + (void *) __LINE__); + } + } + + switch (client) + { + case 0L: + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message!\n"); + break; + case 4L: + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Leaf client %li got a message.\n", + client); + break; + default: + GNUNET_assert (0); + break; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: (%d/%d)\n", ok, ok_goal); + data = (uint32_t *) &message[1]; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, " payload: (%u)\n", ntohl (*data)); + if (SPEED == test && GNUNET_YES == test_backwards) + { + expected_target_client = 0L; + } + else + { + expected_target_client = 4L; + } + + if (GNUNET_NO == initialized) + { + initialized = GNUNET_YES; + start_time = GNUNET_TIME_absolute_get (); + if (SPEED == test) + { + GNUNET_assert (4L == client); + GNUNET_SCHEDULER_add_now (&data_task, NULL); + return GNUNET_OK; + } + } + + if (client == expected_target_client) // Normally 4 + { + data_received++; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received data %u\n", data_received); + if (SPEED != test || (ok_goal - 2) == ok) + { + GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO, + GNUNET_TIME_UNIT_FOREVER_REL, + size_payload, &tmt_rdy, (void *) 1L); + return GNUNET_OK; + } + else + { + if (data_received < TOTAL_PACKETS) + return GNUNET_OK; + } + } + else // Normally 0 + { + if (test == SPEED_ACK || test == SPEED) + { + data_ack++; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received ack %u\n", data_ack); + GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO, + GNUNET_TIME_UNIT_FOREVER_REL, + size_payload, &tmt_rdy, (void *) 1L); + if (data_ack < TOTAL_PACKETS && SPEED != test) + return GNUNET_OK; + if (ok == 2 && SPEED == test) + return GNUNET_OK; + show_end_data(); + } + if (test == P2P_SIGNAL) + { + GNUNET_CADET_channel_destroy (incoming_ch); + incoming_ch = NULL; + } + else + { + GNUNET_CADET_channel_destroy (ch); + ch = NULL; + } + } + + if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, + &disconnect_cadet_peers, + (void *) __LINE__); + } + + return GNUNET_OK; +} + + +/** + * Stats callback. Finish the stats testbed operation and when all stats have + * been iterated, shutdown the test. + * + * @param cls closure + * @param op the operation that has been finished + * @param emsg error message in case the operation has failed; will be NULL if + * operation has executed successfully. + */ +static void +stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "stats_cont for peer %u\n", cls); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, " sent: %u, received: %u\n", + ka_sent, ka_received); + if (ka_sent < 2 || ka_sent > ka_received + 1) + ok--; + GNUNET_TESTBED_operation_done (stats_op); + + if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, + (void *) __LINE__); + +} + + +/** + * Process statistic values. + * + * @param cls closure + * @param peer the peer the statistic belong to + * @param subsystem name of subsystem that created the statistic + * @param name the name of the datum + * @param value the current value + * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not + * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + */ +static int +stats_iterator (void *cls, const struct GNUNET_TESTBED_Peer *peer, + const char *subsystem, const char *name, + uint64_t value, int is_persistent) +{ + static const char *s_sent = "# keepalives sent"; + static const char *s_recv = "# keepalives received"; + uint32_t i; + + i = GNUNET_TESTBED_get_index (peer); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %u - %s [%s]: %llu\n", + i, subsystem, name, value); + if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i) + ka_sent = value; + + if (0 == strncmp(s_recv, name, strlen (s_recv)) && 4 == i) + ka_received = value; + + return GNUNET_OK; +} + + +/** + * Task check that keepalives were sent and received. + * + * @param cls Closure (NULL). + * @param tc Task Context. + */ +static void +check_keepalives (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0) + return; + + disconnect_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "check keepalives\n"); + GNUNET_CADET_channel_destroy (ch); + stats_op = GNUNET_TESTBED_get_statistics (5, testbed_peers, + "cadet", NULL, + stats_iterator, stats_cont, NULL); +} + + +/** + * Handlers, for diverse services + */ +static struct GNUNET_CADET_MessageHandler handlers[] = { + {&data_callback, 1, sizeof (struct GNUNET_MessageHeader)}, + {NULL, 0, 0} +}; + + +/** + * Method called whenever another peer has added us to a channel + * the other peer initiated. + * + * @param cls Closure. + * @param channel New handle to the channel. + * @param initiator Peer that started the channel. + * @param port Port this channel is connected to. + * @param options channel option flags + * @return Initial channel context for the channel + * (can be NULL -- that's not an error). + */ +static void * +incoming_channel (void *cls, struct GNUNET_CADET_Channel *channel, + const struct GNUNET_PeerIdentity *initiator, + uint32_t port, enum GNUNET_CADET_ChannelOption options) +{ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Incoming channel from %s to peer %d\n", + GNUNET_i2s (initiator), (long) cls); + ok++; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); + if ((long) cls == 4L) + incoming_ch = channel; + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Incoming channel for unknown client %lu\n", (long) cls); + GNUNET_break(0); + } + if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + if (KEEPALIVE == test) + { + struct GNUNET_TIME_Relative delay; + delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS , 5); + disconnect_task = + GNUNET_SCHEDULER_add_delayed (delay, &check_keepalives, NULL); + } + else + disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, + &disconnect_cadet_peers, + (void *) __LINE__); + } + + return NULL; +} + +/** + * Function called whenever an inbound channel is destroyed. Should clean up + * any associated state. + * + * @param cls closure (set from GNUNET_CADET_connect) + * @param channel connection to the other end (henceforth invalid) + * @param channel_ctx place where local state associated + * with the channel is stored + */ +static void +channel_cleaner (void *cls, const struct GNUNET_CADET_Channel *channel, + void *channel_ctx) +{ + long i = (long) cls; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Incoming channel disconnected at peer %ld\n", i); + if (4L == i) + { + ok++; + GNUNET_break (channel == incoming_ch); + incoming_ch = NULL; + } + else if (0L == i) + { + if (P2P_SIGNAL == test) + { + ok ++; + } + GNUNET_break (channel == ch); + ch = NULL; + } + else + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Unknown peer! %d\n", i); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); + + if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, + (void *) __LINE__); + } + + return; +} + + +/** + * START THE TESTCASE ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES. + * + * Testcase continues when the root receives confirmation of connected peers, + * on callback funtion ch. + * + * @param cls Closure (unsued). + * @param tc Task Context. + */ +static void +do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + enum GNUNET_CADET_ChannelOption flags; + + if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0) + return; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test_task\n"); + + if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + } + + flags = GNUNET_CADET_OPTION_DEFAULT; + if (SPEED_REL == test) + { + test = SPEED; + flags |= GNUNET_CADET_OPTION_RELIABLE; + } + ch = GNUNET_CADET_channel_create (h1, NULL, p_id[1], 1, flags); + + disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, + &disconnect_cadet_peers, + (void *) __LINE__); + if (KEEPALIVE == test) + return; /* Don't send any data. */ + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending data initializer...\n"); + data_ack = 0; + data_received = 0; + data_sent = 0; + GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO, + GNUNET_TIME_UNIT_FOREVER_REL, + size_payload, &tmt_rdy, (void *) 1L); +} + +/** + * Callback to be called when the requested peer information is available + * + * @param cls the closure from GNUNET_TESTBED_peer_get_information() + * @param op the operation this callback corresponds to + * @param pinfo the result; will be NULL if the operation has failed + * @param emsg error message if the operation has failed; + * NULL if the operation is successfull + */ +static void +pi_cb (void *cls, + struct GNUNET_TESTBED_Operation *op, + const struct GNUNET_TESTBED_PeerInformation *pinfo, + const char *emsg) +{ + long i = (long) cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "id callback for %ld\n", i); + + if (NULL == pinfo || NULL != emsg) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg); + abort_test (__LINE__); + return; + } + p_id[i] = pinfo->result.id; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " id: %s\n", GNUNET_i2s (p_id[i])); + p_ids++; + if (p_ids < 2) + return; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n"); + test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &do_test, NULL); +} + +/** + * test main: start test when all peers are connected + * + * @param cls Closure. + * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end. + * @param num_peers Number of peers that are running. + * @param peers Array of peers. + * @param cadetes Handle to each of the CADETs of the peers. + */ +static void +tmain (void *cls, + struct GNUNET_CADET_TEST_Context *ctx, + unsigned int num_peers, + struct GNUNET_TESTBED_Peer **peers, + struct GNUNET_CADET_Handle **cadetes) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n"); + ok = 0; + test_ctx = ctx; + peers_running = num_peers; + testbed_peers = peers; + h1 = cadetes[0]; + h2 = cadetes[num_peers - 1]; + disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, + &disconnect_cadet_peers, + (void *) __LINE__); + shutdown_handle = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &shutdown_task, NULL); + t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0], + GNUNET_TESTBED_PIT_IDENTITY, + &pi_cb, (void *) 0L); + t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1], + GNUNET_TESTBED_PIT_IDENTITY, + &pi_cb, (void *) 1L); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n"); +} + + +/** + * Main: start test + */ +int +main (int argc, char *argv[]) +{ + initialized = GNUNET_NO; + static uint32_t ports[2]; + const char *config_file; + + GNUNET_log_setup ("test", "DEBUG", NULL); + config_file = "test_cadet.conf"; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start\n"); + if (strstr (argv[0], "_cadet_forward") != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "FORWARD\n"); + test = FORWARD; + test_name = "unicast"; + ok_goal = 4; + } + else if (strstr (argv[0], "_cadet_signal") != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SIGNAL\n"); + test = P2P_SIGNAL; + test_name = "signal"; + ok_goal = 4; + } + else if (strstr (argv[0], "_cadet_speed_ack") != NULL) + { + /* Test is supposed to generate the following callbacks: + * 1 incoming channel (@dest) + * TOTAL_PACKETS received data packet (@dest) + * TOTAL_PACKETS received data packet (@orig) + * 1 received channel destroy (@dest) + */ + ok_goal = TOTAL_PACKETS * 2 + 2; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n"); + test = SPEED_ACK; + test_name = "speed ack"; + } + else if (strstr (argv[0], "_cadet_speed") != NULL) + { + /* Test is supposed to generate the following callbacks: + * 1 incoming channel (@dest) + * 1 initial packet (@dest) + * TOTAL_PACKETS received data packet (@dest) + * 1 received data packet (@orig) + * 1 received channel destroy (@dest) + */ + ok_goal = TOTAL_PACKETS + 4; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n"); + if (strstr (argv[0], "_reliable") != NULL) + { + test = SPEED_REL; + test_name = "speed reliable"; + config_file = "test_cadet_drop.conf"; + } + else + { + test = SPEED; + test_name = "speed"; + } + } + else if (strstr (argv[0], "_keepalive") != NULL) + { + test = KEEPALIVE; + /* Test is supposed to generate the following callbacks: + * 1 incoming channel (@dest) + * [wait] + * 1 received channel destroy (@dest) + */ + ok_goal = 2; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNKNOWN\n"); + test = SETUP; + ok_goal = 0; + } + + if (strstr (argv[0], "backwards") != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "BACKWARDS (LEAF TO ROOT)\n"); + test_backwards = GNUNET_YES; + GNUNET_asprintf (&test_name, "backwards %s", test_name); + } + + p_ids = 0; + ports[0] = 1; + ports[1] = 0; + GNUNET_CADET_TEST_run ("test_cadet_small", + config_file, + 5, + &tmain, + NULL, /* tmain cls */ + &incoming_channel, + &channel_cleaner, + handlers, + ports); + + if (ok_goal > ok) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "FAILED! (%d/%d)\n", ok, ok_goal); + return 1; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n"); + return 0; +} + +/* end of test_cadet.c */ + diff --git a/src/cadet/test_cadet.conf b/src/cadet/test_cadet.conf new file mode 100644 index 000000000..5a2f03dd0 --- /dev/null +++ b/src/cadet/test_cadet.conf @@ -0,0 +1,100 @@ +[testbed] +AUTOSTART = NO +PORT = 12113 +ACCEPT_FROM = 127.0.0.1; +HOSTNAME = localhost +OVERLAY_TOPOLOGY = LINE +#PREFIX = xterm -geometry 100x85 -T peer1 -e libtool --mode=execute gdb --args + +[fs] +AUTOSTART = NO + +[resolver] +AUTOSTART = NO + +[mesh] +#BINARY = gnunet-service-mesh-enc +#PREFIX = valgrind --leak-check=full +#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args +AUTOSTART = NO +ACCEPT_FROM = 127.0.0.1; +REFRESH_CONNECTION_TIME = 2 s +ID_ANNOUNCE_TIME = 5 s +CONNECT_TIMEOUT = 30 s +DEFAULT_TTL = 16 +DHT_REPLICATION_LEVEL = 10 +MAX_TUNNELS = 10 +MAX_CONNECTIONS = 10 +MAX_MSGS_QUEUE = 20 +DISABLE_TRY_CONNECT = YES + +[dht] +AUTOSTART = NO +DISABLE_TRY_CONNECT = YES +FORCE_NSE = 3 + +[dhtcache] +QUOTA = 1 MB +DATABASE = heap + +[transport] +PLUGINS = udp +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +NEIGHBOUR_LIMIT = 50 +PORT = 12365 +#MANIPULATE_DELAY_IN = 10 ms +#MANIPULATE_DELAY_OUT = 10 ms + + +[ats] +WAN_QUOTA_OUT = 3932160 +WAN_QUOTA_IN = 3932160 + +[core] +PORT = 12092 +AUTOSTART = YES +USE_EPHEMERAL_KEYS = NO + +[arm] +DEFAULTSERVICES = core transport dht mesh statistics +PORT = 12366 + +[transport-udp] +TIMEOUT = 300 s +PORT = 12368 + +[gnunetd] +HOSTKEY = $GNUNET_TEST_HOME/.hostkey + +[PATHS] +GNUNET_TEST_HOME = /tmp/test-mesh/ + +[dns] +AUTOSTART = NO + +[nse] +AUTOSTART = NO + +[vpn] +AUTOSTART = NO + +[nat] +RETURN_LOCAL_ADDRESSES = YES +DISABLEV6 = YES +USE_LOCALADDR = YES + +[gns-helper-service-w32] +AUTOSTART = NO + +[consensus] +AUTOSTART = NO + +[gns] +AUTOSTART = NO + +[statistics] +AUTOSTART = NO + +[peerinfo] +NO_IO = YES diff --git a/src/cadet/test_cadet_drop.conf b/src/cadet/test_cadet_drop.conf new file mode 100644 index 000000000..4df0e3f34 --- /dev/null +++ b/src/cadet/test_cadet_drop.conf @@ -0,0 +1,4 @@ +@INLINE@ test_mesh.conf + +[mesh] +DROP_PERCENT = 1 diff --git a/src/cadet/test_cadet_local.c b/src/cadet/test_cadet_local.c new file mode 100644 index 000000000..0796aaf12 --- /dev/null +++ b/src/cadet/test_cadet_local.c @@ -0,0 +1,337 @@ +/* + 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 cadet/test_cadet_local.c + * @brief test cadet local: test of cadet channels with just one peer + * @author Bartlomiej Polot + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_dht_service.h" +#include "gnunet_testing_lib.h" +#include "gnunet_cadet_service.h" + +struct GNUNET_TESTING_Peer *me; + +static struct GNUNET_CADET_Handle *cadet_peer_1; + +static struct GNUNET_CADET_Handle *cadet_peer_2; + +static struct GNUNET_CADET_Channel *ch; + +static int result = GNUNET_OK; + +static int got_data = GNUNET_NO; + +static GNUNET_SCHEDULER_TaskIdentifier abort_task; + +static GNUNET_SCHEDULER_TaskIdentifier shutdown_task; + +static struct GNUNET_CADET_TransmitHandle *mth; + + +/** + * Connect to other client and send data + * + * @param cls Closue (unused). + * @param tc TaskContext. + */ +static void +do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Shutdown nicely + */ +static void +do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutdown\n"); + if (GNUNET_SCHEDULER_NO_TASK != abort_task) + { + GNUNET_SCHEDULER_cancel (abort_task); + } + if (NULL != ch) + { + GNUNET_CADET_channel_destroy (ch); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect client 1\n"); + if (NULL != cadet_peer_1) + { + GNUNET_CADET_disconnect (cadet_peer_1); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect client 2\n"); + if (NULL != cadet_peer_2) + { + GNUNET_CADET_disconnect (cadet_peer_2); + } +} + + +/** + * Something went wrong and timed out. Kill everything and set error flag + */ +static void +do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ABORT\n"); + result = GNUNET_SYSERR; + abort_task = GNUNET_SCHEDULER_NO_TASK; + if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) + { + GNUNET_SCHEDULER_cancel (shutdown_task); + shutdown_task = GNUNET_SCHEDULER_NO_TASK; + } + do_shutdown (cls, tc); +} + + +/** + * Function is called whenever a message is received. + * + * @param cls closure (set from GNUNET_CADET_connect) + * @param channel connection to the other end + * @param channel_ctx place to store local state associated with the channel + * @param message the actual message + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +data_callback (void *cls, struct GNUNET_CADET_Channel *channel, + void **channel_ctx, + const struct GNUNET_MessageHeader *message) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data callback! Shutting down.\n"); + got_data = GNUNET_YES; + if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) + GNUNET_SCHEDULER_cancel (shutdown_task); + shutdown_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_shutdown, + NULL); + GNUNET_CADET_receive_done (channel); + return GNUNET_OK; +} + + +/** + * Method called whenever another peer has added us to a channel + * the other peer initiated. + * + * @param cls closure + * @param channel new handle to the channel + * @param initiator peer that started the channel + * @param port port number + * @param options channel options + * @return initial channel context for the channel + * (can be NULL -- that's not an error) + */ +static void * +inbound_channel (void *cls, struct GNUNET_CADET_Channel *channel, + const struct GNUNET_PeerIdentity *initiator, + uint32_t port, enum GNUNET_CADET_ChannelOption options) +{ + long id = (long) cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "received incoming channel on peer %d, port %u\n", + id, port); + if (id != 2L) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "wrong peer\n"); + result = GNUNET_SYSERR; + } + return NULL; +} + + +/** + * Function called whenever an channel is destroyed. Should clean up + * any associated state. + * + * @param cls closure (set from GNUNET_CADET_connect) + * @param channel connection to the other end (henceforth invalid) + * @param channel_ctx place where local state associated + * with the channel is stored + */ +static void +channel_end (void *cls, const struct GNUNET_CADET_Channel *channel, + void *channel_ctx) +{ + long id = (long) cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "incoming channel closed at peer %ld\n", + id); + if (NULL != mth) + { + GNUNET_CADET_notify_transmit_ready_cancel (mth); + mth = NULL; + } + if (GNUNET_NO == got_data) + { + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply ( + GNUNET_TIME_UNIT_SECONDS, + 2), + &do_connect, NULL); + } +} + + +/** + * Handler array for traffic received on peer1 + */ +static struct GNUNET_CADET_MessageHandler handlers1[] = { + {&data_callback, 1, 0}, + {NULL, 0, 0} +}; + + +/** + * Handler array for traffic received on peer2 (none expected) + */ +static struct GNUNET_CADET_MessageHandler handlers2[] = { + {&data_callback, 1, 0}, + {NULL, 0, 0} +}; + + +/** + * Data send callback: fillbuffer with test packet. + * + * @param cls Closure (unused). + * @param size Buffer size. + * @param buf Buffer to fill. + * + * @return size of test packet. + */ +static size_t +do_send (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader *m = buf; + + mth = NULL; + if (NULL == buf) + { + GNUNET_break (0); + result = GNUNET_SYSERR; + return 0; + } + m->size = htons (sizeof (struct GNUNET_MessageHeader)); + m->type = htons (1); + GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); + return sizeof (struct GNUNET_MessageHeader); +} + +/** + * Connect to other client and send data + * + * @param cls Closue (unused). + * @param tc TaskContext. + */ +static void +do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_PeerIdentity id; + + if (NULL != tc && 0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) + return; + + GNUNET_TESTING_peer_get_identity (me, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CONNECT BY PORT\n"); + ch = GNUNET_CADET_channel_create (cadet_peer_1, NULL, &id, 1, + GNUNET_CADET_OPTION_DEFAULT); + mth = GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO, + GNUNET_TIME_UNIT_FOREVER_REL, + sizeof (struct GNUNET_MessageHeader), + &do_send, NULL); +} + + +/** + * Initialize framework and start test + * + * @param cls Closure (unused). + * @param cfg Configuration handle. + * @param peer Testing peer handle. + */ +static void +run (void *cls, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Peer *peer) +{ + static uint32_t ports[] = {1, 0}; + + me = peer; + abort_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 15), &do_abort, + NULL); + cadet_peer_1 = GNUNET_CADET_connect (cfg, /* configuration */ + (void *) 1L, /* cls */ + NULL, /* inbound new hndlr */ + &channel_end, /* channel end hndlr */ + handlers1, /* traffic handlers */ + NULL); /* ports offered */ + + cadet_peer_2 = GNUNET_CADET_connect (cfg, /* configuration */ + (void *) 2L, /* cls */ + &inbound_channel, /* inbound new hndlr */ + &channel_end, /* channel end hndlr */ + handlers2, /* traffic handlers */ + ports); /* ports offered */ + if (NULL == cadet_peer_1 || NULL == cadet_peer_2) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Couldn't connect to cadet :(\n"); + result = GNUNET_SYSERR; + return; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "YAY! CONNECTED TO CADET :D\n"); + } + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply ( + GNUNET_TIME_UNIT_SECONDS, + 2), + &do_connect, NULL); +} + + +/** + * Main + */ +int +main (int argc, char *argv[]) +{ + if (0 != GNUNET_TESTING_peer_run ("test-cadet-local", + "test_cadet.conf", + &run, NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "run failed\n"); + return 2; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Final result: %d\n", result); + return (result == GNUNET_OK) ? 0 : 1; +} + +/* end of test_cadet_local_1.c */ diff --git a/src/cadet/test_cadet_single.c b/src/cadet/test_cadet_single.c new file mode 100644 index 000000000..3780c745c --- /dev/null +++ b/src/cadet/test_cadet_single.c @@ -0,0 +1,329 @@ +/* + 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 cadet/test_cadet_single.c + * @brief test cadet single: test of cadet channels with just one client + * @author Bartlomiej Polot + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_dht_service.h" +#include "gnunet_testing_lib.h" +#include "gnunet_cadet_service.h" + +#define REPETITIONS 5 +#define DATA_SIZE 35000 + +struct GNUNET_TESTING_Peer *me; + +static struct GNUNET_CADET_Handle *cadet; + +static struct GNUNET_CADET_Channel *ch1; + +static struct GNUNET_CADET_Channel *ch2; + +static int result; + +static GNUNET_SCHEDULER_TaskIdentifier abort_task; + +static GNUNET_SCHEDULER_TaskIdentifier shutdown_task; + +static unsigned int repetition; + + +/* forward declaration */ +static size_t +do_send (void *cls, size_t size, void *buf); + + +/** + * Shutdown nicely + */ +static void +do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutdown\n"); + if (GNUNET_SCHEDULER_NO_TASK != abort_task) + { + GNUNET_SCHEDULER_cancel (abort_task); + } + if (NULL != ch1) + { + GNUNET_CADET_channel_destroy (ch1); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect client 1\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect client 2\n"); + if (NULL != cadet) + { + GNUNET_CADET_disconnect (cadet); + cadet = NULL; + } + else + { + GNUNET_break (0); + } +} + + +/** + * Something went wrong and timed out. Kill everything and set error flag + */ +static void +do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ABORT\n"); + result = GNUNET_SYSERR; + abort_task = GNUNET_SCHEDULER_NO_TASK; + if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) + { + GNUNET_SCHEDULER_cancel (shutdown_task); + shutdown_task = GNUNET_SCHEDULER_NO_TASK; + } + do_shutdown (cls, tc); +} + + +static void +finish (void) +{ + if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) + GNUNET_SCHEDULER_cancel (shutdown_task); + shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &do_shutdown, NULL); +} + + +/** + * Function is called whenever a message is received. + * + * @param cls closure (set from GNUNET_CADET_connect) + * @param channel connection to the other end + * @param channel_ctx place to store local state associated with the channel + * @param message the actual message + * + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +data_callback (void *cls, struct GNUNET_CADET_Channel *channel, + void **channel_ctx, + const struct GNUNET_MessageHeader *message) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Data callback! Repetition %u/%u\n", + repetition, REPETITIONS); + repetition = repetition + 1; + if (repetition < REPETITIONS) + { + struct GNUNET_CADET_Channel *my_channel; + if (repetition % 2 == 0) + my_channel = ch1; + else + my_channel = ch2; + GNUNET_CADET_notify_transmit_ready (my_channel, GNUNET_NO, + GNUNET_TIME_UNIT_FOREVER_REL, + sizeof (struct GNUNET_MessageHeader) + + DATA_SIZE, + &do_send, NULL); + GNUNET_CADET_receive_done (channel); + return GNUNET_OK; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All data OK. Destroying channel.\n"); + GNUNET_CADET_channel_destroy (ch1); + ch1 = NULL; + return GNUNET_OK; +} + + +/** + * Method called whenever another peer has added us to a channel + * the other peer initiated. + * + * @param cls closure + * @param channel new handle to the channel + * @param initiator peer that started the channel + * @param port port number + * @param options channel option flags + * @return initial channel context for the channel + * (can be NULL -- that's not an error) + */ +static void * +inbound_channel (void *cls, struct GNUNET_CADET_Channel *channel, + const struct GNUNET_PeerIdentity *initiator, + uint32_t port, enum GNUNET_CADET_ChannelOption options) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "received incoming channel on port %u\n", + port); + ch2 = channel; + return NULL; +} + + +/** + * Function called whenever an inbound channel is destroyed. Should clean up + * any associated state. + * + * @param cls closure (set from GNUNET_CADET_connect) + * @param channel connection to the other end (henceforth invalid) + * @param channel_ctx place where local state associated + * with the channel is stored + */ +static void +channel_end (void *cls, const struct GNUNET_CADET_Channel *channel, + void *channel_ctx) +{ + long id = (long) cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "incoming channel closed at peer %ld\n", + id); + if (REPETITIONS == repetition && channel == ch2) + { + ch2 = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "everything fine! finishing!\n"); + result = GNUNET_OK; + finish (); + } +} + + +/** + * Handler array for traffic received on peer1 + */ +static struct GNUNET_CADET_MessageHandler handlers1[] = { + {&data_callback, 1, 0}, + {NULL, 0, 0} +}; + + +/** + * Data send callback: fillbuffer with test packet. + * + * @param cls Closure (unused). + * @param size Buffer size. + * @param buf Buffer to fill. + * + * @return size of test packet. + */ +static size_t +do_send (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader *m = buf; + + if (NULL == buf) + { + GNUNET_break (0); + result = GNUNET_SYSERR; + return 0; + } + m->size = htons (sizeof (struct GNUNET_MessageHeader)); + m->type = htons (1); + memset (&m[1], 0, DATA_SIZE); + GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader) + DATA_SIZE); + return sizeof (struct GNUNET_MessageHeader) + DATA_SIZE; +} + +/** + * Connect to other client and send data + * + * @param cls Closue (unused). + * @param tc TaskContext. + */ +static void +do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_PeerIdentity id; + size_t size = sizeof (struct GNUNET_MessageHeader) + DATA_SIZE; + + if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0) + return; + + GNUNET_TESTING_peer_get_identity (me, &id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CONNECT BY PORT\n"); + ch1 = GNUNET_CADET_channel_create (cadet, NULL, &id, 1, + GNUNET_CADET_OPTION_DEFAULT); + GNUNET_CADET_notify_transmit_ready (ch1, GNUNET_NO, + GNUNET_TIME_UNIT_FOREVER_REL, + size, &do_send, NULL); +} + + +/** + * Initialize framework and start test + * + * @param cls Closure (unused). + * @param cfg Configuration handle. + * @param peer Testing peer handle. + */ +static void +run (void *cls, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Peer *peer) +{ + static uint32_t ports[] = {1, 0}; + + me = peer; + abort_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 15), &do_abort, + NULL); + cadet = GNUNET_CADET_connect (cfg, /* configuration */ + (void *) 1L, /* cls */ + &inbound_channel, /* inbound new hndlr */ + &channel_end, /* inbound end hndlr */ + handlers1, /* traffic handlers */ + ports); /* ports offered */ + + if (NULL == cadet) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Couldn't connect to cadet :(\n"); + result = GNUNET_SYSERR; + return; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "YAY! CONNECTED TO CADET :D\n"); + } + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_connect, NULL); +} + + +/** + * Main + */ +int +main (int argc, char *argv[]) +{ + result = GNUNET_NO; + if (0 != GNUNET_TESTING_peer_run ("test-cadet-local", + "test_cadet.conf", + &run, NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "run failed\n"); + return 2; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Final result: %d\n", result); + return (result == GNUNET_OK) ? 0 : 1; +} + +/* end of test_cadet_single.c */ diff --git a/src/cadet/valgrind-mesh.supp b/src/cadet/valgrind-mesh.supp new file mode 100644 index 000000000..fecd5185b --- /dev/null +++ b/src/cadet/valgrind-mesh.supp @@ -0,0 +1,116 @@ +{ + logsetup_addr + Memcheck:Addr8 + obj:/lib/libc-2.14.1.so + ... + fun:get_type + fun:GNUNET_log_setup + fun:GNUNET_SERVICE_run + fun:main +} + +{ + scanf_addr + Memcheck:Addr8 + obj:/lib/libc-2.14.1.so + ... + fun:vsscanf + fun:sscanf + fun:GNUNET_CONFIGURATION_get_value_number + fun:GNUNET_SERVICE_get_server_addresses + fun:setup_service + fun:GNUNET_SERVICE_run + fun:main +} + +{ + mylog_addr + Memcheck:Addr8 + obj:/lib/libc-2.14.1.so + ... + fun:service_task + fun:GNUNET_SCHEDULER_run + fun:GNUNET_SERVICE_run + fun:main +} + +{ + mylog_uninit + Memcheck:Value8 + obj:/lib/libc-2.14.1.so + ... + fun:mylog + fun:GNUNET_log_from_nocheck + fun:service_task + ... + fun:GNUNET_SCHEDULER_run + fun:GNUNET_SERVICE_run + fun:main +} + +{ + mylog_from_cond + Memcheck:Cond + obj:/lib/libc-2.14.1.so + ... + fun:mylog + fun:GNUNET_log_from_nocheck + ... + fun:service_task + fun:GNUNET_SCHEDULER_run + fun:GNUNET_SERVICE_run + fun:main +} + +{ + mylog_cond + Memcheck:Cond + obj:/lib/libc-2.14.1.so + ... + fun:mylog + fun:GNUNET_log_nocheck + ... + fun:service_task + fun:GNUNET_SCHEDULER_run + fun:GNUNET_SERVICE_run + fun:main +} + +{ + inet_ntop_cond + Memcheck:Cond + obj:/lib/libc-2.14.1.so + ... + fun:inet_ntop + fun:GNUNET_a2s + ... + fun:service_task + fun:GNUNET_SCHEDULER_run + fun:GNUNET_SERVICE_run + fun:main +} + +{ + create_key_from_file + Memcheck:Addr8 + obj:/lib/libc-2.14.1.so + ... + fun:GNUNET_CRYPTO_rsa_key_create_from_file + fun:run + fun:service_task + fun:GNUNET_SCHEDULER_run + fun:GNUNET_SERVICE_run + fun:main +} + +{ + main_notify_handler + Memcheck:Addr8 + obj:/lib/libc-2.14.1.so + ... + fun:main_notify_handler + fun:receive_ready + fun:GNUNET_SCHEDULER_run + fun:GNUNET_SERVICE_run + fun:main +} \ No newline at end of file diff --git a/src/mesh/Makefile.am b/src/mesh/Makefile.am deleted file mode 100644 index e9aaec402..000000000 --- a/src/mesh/Makefile.am +++ /dev/null @@ -1,194 +0,0 @@ -AM_CPPFLAGS = -I$(top_srcdir)/src/include - -if MINGW - WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -endif - -if USE_COVERAGE - AM_CFLAGS = --coverage -O0 - XLIB = -lgcov -endif - -pkgcfgdir= $(pkgdatadir)/config.d/ - -libexecdir= $(pkglibdir)/libexec/ - -pkgcfg_DATA = \ - cadet.conf - -plugindir = $(libdir)/gnunet - -AM_CLFAGS = -g - -libexec_PROGRAMS = \ - gnunet-service-cadet $(EXP_LIBEXEC) - -bin_PROGRAMS = \ - gnunet-cadet - -lib_LTLIBRARIES = \ - libgnunetcadet.la $(EXP_LIB) - -libgnunetcadet_la_SOURCES = \ - cadet_api.c cadet_common.c -libgnunetcadet_la_LIBADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(XLIB) \ - $(LTLIBINTL) -libgnunetcadet_la_LDFLAGS = \ - $(GN_LIB_LDFLAGS) $(WINFLAGS) \ - -version-info 5:0:0 - -gnunet_cadet_SOURCES = \ - gnunet-cadet.c -gnunet_cadet_LDADD = \ - $(top_builddir)/src/cadet/libgnunetcadet.la \ - $(top_builddir)/src/util/libgnunetutil.la -gnunet_cadet_DEPENDENCIES = \ - libgnunetcadet.la - -gnunet_service_cadet_SOURCES = \ - gnunet-service-cadet_tunnel.c gnunet-service-cadet_tunnel.h \ - gnunet-service-cadet_connection.c gnunet-service-cadet_connection.h \ - gnunet-service-cadet_channel.c gnunet-service-cadet_channel.h \ - gnunet-service-cadet_local.c gnunet-service-cadet_local.h \ - gnunet-service-cadet_peer.c gnunet-service-cadet_peer.h \ - gnunet-service-cadet_dht.c gnunet-service-cadet_dht.h \ - gnunet-service-cadet_hello.c gnunet-service-cadet_hello.h \ - cadet_path.c cadet_path.h \ - cadet_common.c \ - gnunet-service-cadet.c -gnunet_service_cadet_CFLAGS = $(AM_CFLAGS) -gnunet_service_cadet_LDADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/transport/libgnunettransport.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/dht/libgnunetdht.la \ - $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ - $(top_builddir)/src/hello/libgnunethello.la \ - $(top_builddir)/src/block/libgnunetblock.la -gnunet_service_cadet_DEPENDENCIES = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/transport/libgnunettransport.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/dht/libgnunetdht.la \ - $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ - $(top_builddir)/src/hello/libgnunethello.la \ - $(top_builddir)/src/block/libgnunetblock.la -if LINUX - gnunet_service_cadet_LDFLAGS = -lrt -endif - - -if HAVE_TESTING - noinst_LIBRARIES = libgnunetcadettest.a $(noinst_LIB_EXP) - noinst_PROGRAMS = gnunet-cadet-profiler -endif - -libgnunetcadettest_a_SOURCES = \ - cadet_test_lib.c cadet_test_lib.h -libgnunetcadettest_a_LIBADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/testbed/libgnunettestbed.la \ - $(top_builddir)/src/cadet/libgnunetcadet.la -libgnunetcadettest_a_DEPENDENCIES = \ - libgnunetcadet.la - -if HAVE_TESTING -check_PROGRAMS = \ - test_cadet_single \ - test_cadet_local \ - test_cadet_forward \ - test_cadet_signal \ - test_cadet_keepalive \ - test_cadet_speed \ - test_cadet_speed_ack \ - test_cadet_speed_backwards \ - test_cadet_speed_reliable \ - test_cadet_speed_reliable_backwards -endif - -ld_cadet_test_lib = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/cadet/libgnunetcadettest.a \ - $(top_builddir)/src/cadet/libgnunetcadet.la \ - $(top_builddir)/src/testbed/libgnunettestbed.la \ - $(top_builddir)/src/statistics/libgnunetstatistics.la - -dep_cadet_test_lib = \ - libgnunetcadet.la \ - libgnunetcadettest.a \ - $(top_builddir)/src/statistics/libgnunetstatistics.la - - -gnunet_cadet_profiler_SOURCES = \ - gnunet-cadet-profiler.c -gnunet_cadet_profiler_LDADD = $(ld_cadet_test_lib) -gnunet_cadet_profiler_DEPENDENCIES = $(dep_cadet_test_lib) - - -test_cadet_single_SOURCES = \ - test_cadet_single.c -test_cadet_single_LDADD = $(ld_cadet_test_lib) -test_cadet_single_DEPENDENCIES = $(dep_cadet_test_lib) - -test_cadet_local_SOURCES = \ - test_cadet_local.c -test_cadet_local_LDADD = $(ld_cadet_test_lib) -test_cadet_local_DEPENDENCIES = $(dep_cadet_test_lib) - -test_cadet_forward_SOURCES = \ - test_cadet.c -test_cadet_forward_LDADD = $(ld_cadet_test_lib) -test_cadet_forward_DEPENDENCIES = $(dep_cadet_test_lib) - -test_cadet_signal_SOURCES = \ - test_cadet.c -test_cadet_signal_LDADD = $(ld_cadet_test_lib) -test_cadet_signal_DEPENDENCIES = $(dep_cadet_test_lib) - -test_cadet_keepalive_SOURCES = \ - test_cadet.c -test_cadet_keepalive_LDADD = $(ld_cadet_test_lib) -test_cadet_keepalive_DEPENDENCIES = $(dep_cadet_test_lib) - -test_cadet_speed_SOURCES = \ - test_cadet.c -test_cadet_speed_LDADD = $(ld_cadet_test_lib) -test_cadet_speed_DEPENDENCIES = $(dep_cadet_test_lib) - -test_cadet_speed_ack_SOURCES = \ - test_cadet.c -test_cadet_speed_ack_LDADD = $(ld_cadet_test_lib) -test_cadet_speed_ack_DEPENDENCIES = $(dep_cadet_test_lib) - -test_cadet_speed_backwards_SOURCES = \ - test_cadet.c -test_cadet_speed_backwards_LDADD = $(ld_cadet_test_lib) -test_cadet_speed_backwards_DEPENDENCIES = $(dep_cadet_test_lib) - -test_cadet_speed_reliable_SOURCES = \ - test_cadet.c -test_cadet_speed_reliable_LDADD = $(ld_cadet_test_lib) -test_cadet_speed_reliable_DEPENDENCIES = $(dep_cadet_test_lib) - -test_cadet_speed_reliable_backwards_SOURCES = \ - test_cadet.c -test_cadet_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib) -test_cadet_speed_reliable_backwards_DEPENDENCIES = $(dep_cadet_test_lib) - - -if ENABLE_TEST_RUN -AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; -TESTS = \ - $(check_PROGRAMS) -endif - -EXTRA_DIST = \ - cadet.h cadet_protocol.h \ - test_cadet.conf \ - test_cadet_drop.conf - diff --git a/src/mesh/beautify_log.sh b/src/mesh/beautify_log.sh deleted file mode 100755 index b12f20380..000000000 --- a/src/mesh/beautify_log.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh -grep "STARTING SERVICE " log > __tmp_peers -SED_EXPR="" -while read -r line; do - PEER=`echo $line | sed -e 's/.*\[\(....\)\].*/\1/'` - PID=`echo $line | sed -e 's/.*mesh-\([0-9]*\).*/\1/'` - echo "$PID => $PEER" - SED_EXPR="${SED_EXPR}s/mesh-\([a-z2]*\)-$PID/MESH \1 $PEER/;" - SED_EXPR="${SED_EXPR}s/mesh-$PID/MESH XXX $PEER/;" -done < __tmp_peers -rm __tmp_peers - -SED_EXPR="${SED_EXPR}s/mesh-api-/mesh-api- /g" -sed -e "$SED_EXPR" log > .log - -if [[ "`ps aux | grep "kwrite .lo[g]"`" = "" ]]; then - kwrite .log --geometry 960x1140-960 & -fi diff --git a/src/mesh/cadet.h b/src/mesh/cadet.h deleted file mode 100644 index 757f8c501..000000000 --- a/src/mesh/cadet.h +++ /dev/null @@ -1,351 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2001 - 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. -*/ - -/** - * @author Bartlomiej Polot - * @file cadet/cadet.h - */ - -#ifndef CADET_H_ -#define CADET_H_ - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include - -#define CADET_DEBUG GNUNET_YES - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_peer_lib.h" -#include "gnunet_core_service.h" -#include "gnunet_protocols.h" -#include - -/******************************************************************************/ -/************************** CONSTANTS ******************************/ -/******************************************************************************/ - -#define GNUNET_CADET_LOCAL_CHANNEL_ID_CLI 0x80000000 -#define GNUNET_CADET_LOCAL_CHANNEL_ID_SERV 0xB0000000 - -#define HIGH_PID 0xFFFF0000 -#define LOW_PID 0x0000FFFF - -#define PID_OVERFLOW(pid, max) (pid > HIGH_PID && max < LOW_PID) - -/******************************************************************************/ -/************************** MESSAGES ******************************/ -/******************************************************************************/ - -GNUNET_NETWORK_STRUCT_BEGIN - -/** - * Message for a client to register to the service - */ -struct GNUNET_CADET_ClientConnect -{ - /** - * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT - * - * Size: sizeof(struct GNUNET_CADET_ClientConnect) + - * sizeof(CADET_ApplicationType) * applications + - * sizeof(uint16_t) * types - */ - struct GNUNET_MessageHeader header; - /* uint32_t list_ports[] */ -}; - - -/** - * Type for channel numbering. - * - Local channel numbers given by the service (incoming) are >= 0xB0000000 - * - Local channel numbers given by the client (created) are >= 0x80000000 - * - Global channel numbers are < 0x80000000 - */ -typedef uint32_t CADET_ChannelNumber; - - -/** - * Message for a client to create and destroy channels. - */ -struct GNUNET_CADET_ChannelMessage -{ - /** - * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_TUNNEL_[CREATE|DESTROY] - * - * Size: sizeof(struct GNUNET_CADET_ChannelMessage) - */ - struct GNUNET_MessageHeader header; - - /** - * ID of a channel controlled by this client. - */ - CADET_ChannelNumber channel_id GNUNET_PACKED; - - /** - * Channel's peer - */ - struct GNUNET_PeerIdentity peer; - - /** - * Port of the channel. - */ - uint32_t port GNUNET_PACKED; - - /** - * Options. - */ - uint32_t opt GNUNET_PACKED; -}; - - -/** - * Message for cadet data traffic. - */ -struct GNUNET_CADET_LocalData -{ - /** - * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA - */ - struct GNUNET_MessageHeader header; - - /** - * ID of the channel - */ - uint32_t id GNUNET_PACKED; - - /** - * Payload follows - */ -}; - - -/** - * Message to allow the client send more data to the service - * (always service -> client). - */ -struct GNUNET_CADET_LocalAck -{ - /** - * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK - */ - struct GNUNET_MessageHeader header; - - /** - * ID of the channel allowed to send more data. - */ - CADET_ChannelNumber channel_id GNUNET_PACKED; - -}; - - -/** - * Message to inform the client about channels in the service. - */ -struct GNUNET_CADET_LocalInfo -{ - /** - * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO[_TUNNEL,_PEER] - */ - struct GNUNET_MessageHeader header; - - /** - * ID of the channel allowed to send more data. - */ - CADET_ChannelNumber channel_id GNUNET_PACKED; - - /** - * ID of the owner of the channel (can be local peer). - */ -// struct GNUNET_PeerIdentity owner; - - /** - * ID of the destination of the channel (can be local peer). - */ - struct GNUNET_PeerIdentity peer; -}; - - -/** - * Message to inform the client about one of the peers in the service. - */ -struct GNUNET_CADET_LocalInfoPeer -{ - /** - * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER[S] - */ - struct GNUNET_MessageHeader header; - - /** - * Number of paths. - */ - uint16_t paths GNUNET_PACKED; - - /** - * Do we have a tunnel toward this peer? - */ - int16_t tunnel GNUNET_PACKED; - - /** - * ID of the destination of the tunnel (can be local peer). - */ - struct GNUNET_PeerIdentity destination; - - /* If type == PEER (no 'S'): GNUNET_PeerIdentity paths[] - * (each path ends in destination) */ -}; - -/** - * Message to inform the client about one of the tunnels in the service. - */ -struct GNUNET_CADET_LocalInfoTunnel -{ - /** - * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL[S] - */ - struct GNUNET_MessageHeader header; - - /** - * Number of channels. - */ - uint32_t channels GNUNET_PACKED; - - /** - * ID of the destination of the tunnel (can be local peer). - */ - struct GNUNET_PeerIdentity destination; - - /** - * Number of connections. - */ - uint32_t connections GNUNET_PACKED; - - /** - * Encryption state. - */ - uint16_t estate GNUNET_PACKED; - - /** - * Connection state. - */ - uint16_t cstate GNUNET_PACKED; - - /* If TUNNEL (no 'S'): GNUNET_PeerIdentity connection_ids[connections] */ - /* If TUNNEL (no 'S'): uint32_t channel_ids[channels] */ -}; - - -GNUNET_NETWORK_STRUCT_END - - - -/** - * @brief Translate a fwd variable into a string representation, for logging. - * - * @param fwd Is FWD? (#GNUNET_YES or #GNUNET_NO) - * - * @return String representing FWD or BCK. - */ -char * -GM_f2s (int fwd); - - -/** - * Check if one pid is bigger than other, accounting for overflow. - * - * @param bigger Argument that should be bigger. - * @param smaller Argument that should be smaller. - * - * @return True if bigger (arg1) has a higher value than smaller (arg 2). - */ -int -GM_is_pid_bigger (uint32_t bigger, uint32_t smaller); - - -/** - * Get the higher ACK value out of two values, taking in account overflow. - * - * @param a First ACK value. - * @param b Second ACK value. - * - * @return Highest ACK value from the two. - */ -uint32_t -GM_max_pid (uint32_t a, uint32_t b); - - -/** - * Get the lower ACK value out of two values, taking in account overflow. - * - * @param a First ACK value. - * @param b Second ACK value. - * - * @return Lowest ACK value from the two. - */ -uint32_t -GM_min_pid (uint32_t a, uint32_t b); - - -/** - * Convert a 256 bit CadetHash into a 512 HashCode to use in GNUNET_h2s, - * multihashmap, and other HashCode-based functions. - * - * @param id A 256 bit hash to expand. - * - * @return A HashCode containing the original 256 bit hash right-padded with 0. - */ -const struct GNUNET_HashCode * -GM_h2hc (const struct GNUNET_CADET_Hash *id); - -/** - * Get a string from a Cadet Hash (256 bits). - * WARNING: Not reentrant (based on GNUNET_h2s). - */ -const char * -GM_h2s (const struct GNUNET_CADET_Hash *id); - -/** - * Convert a message type into a string to help debug - * Generated with: - * FIND: "#define ([^ ]+)[ ]*([0-9]+)" - * REPLACE: " case \2: return "\1"; break;" - * - * @param m Message type. - * - * @return Human readable string description. - */ -const char * -GM_m2s (uint16_t m); - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/mesh/cadet_api.c b/src/mesh/cadet_api.c deleted file mode 100644 index aa5c67329..000000000 --- a/src/mesh/cadet_api.c +++ /dev/null @@ -1,2141 +0,0 @@ -/* - 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 cadet/cadet_api.c - * @brief cadet api: client implementation of new cadet service - * @author Bartlomiej Polot - */ - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_cadet_service.h" -#include "cadet.h" -#include "cadet_protocol.h" - -#define LOG(kind,...) GNUNET_log_from (kind, "cadet-api",__VA_ARGS__) - -/******************************************************************************/ -/************************ DATA STRUCTURES ****************************/ -/******************************************************************************/ - -/** - * Transmission queue to the service - */ -struct GNUNET_CADET_TransmitHandle -{ - - /** - * Double Linked list - */ - struct GNUNET_CADET_TransmitHandle *next; - - /** - * Double Linked list - */ - struct GNUNET_CADET_TransmitHandle *prev; - - /** - * Channel this message is sent on / for (may be NULL for control messages). - */ - struct GNUNET_CADET_Channel *channel; - - /** - * Callback to obtain the message to transmit, or NULL if we - * got the message in 'data'. Notice that messages built - * by 'notify' need to be encapsulated with information about - * the 'target'. - */ - GNUNET_CONNECTION_TransmitReadyNotify notify; - - /** - * Closure for 'notify' - */ - void *notify_cls; - - /** - * How long is this message valid. Once the timeout has been - * reached, the message must no longer be sent. If this - * is a message with a 'notify' callback set, the 'notify' - * function should be called with 'buf' NULL and size 0. - */ - struct GNUNET_TIME_Absolute timeout; - - /** - * Task triggering a timeout, can be NO_TASK if the timeout is FOREVER. - */ - GNUNET_SCHEDULER_TaskIdentifier timeout_task; - - /** - * Size of 'data' -- or the desired size of 'notify' if 'data' is NULL. - */ - size_t size; -}; - -union CadetInfoCB { - - /** - * Channel callback. - */ - GNUNET_CADET_ChannelCB channel_cb; - - /** - * Monitor callback - */ - GNUNET_CADET_PeersCB peers_cb; - - /** - * Monitor callback - */ - GNUNET_CADET_PeerCB peer_cb; - - /** - * Monitor callback - */ - GNUNET_CADET_TunnelsCB tunnels_cb; - - /** - * Tunnel callback. - */ - GNUNET_CADET_TunnelCB tunnel_cb; -}; - - -/** - * Opaque handle to the service. - */ -struct GNUNET_CADET_Handle -{ - - /** - * Handle to the server connection, to send messages later - */ - struct GNUNET_CLIENT_Connection *client; - - /** - * Set of handlers used for processing incoming messages in the channels - */ - const struct GNUNET_CADET_MessageHandler *message_handlers; - - /** - * Number of handlers in the handlers array. - */ - unsigned int n_handlers; - - /** - * Ports open. - */ - const uint32_t *ports; - - /** - * Number of ports. - */ - unsigned int n_ports; - - /** - * Double linked list of the channels this client is connected to, head. - */ - struct GNUNET_CADET_Channel *channels_head; - - /** - * Double linked list of the channels this client is connected to, tail. - */ - struct GNUNET_CADET_Channel *channels_tail; - - /** - * Callback for inbound channel creation - */ - GNUNET_CADET_InboundChannelNotificationHandler *new_channel; - - /** - * Callback for inbound channel disconnection - */ - GNUNET_CADET_ChannelEndHandler *cleaner; - - /** - * Handle to cancel pending transmissions in case of disconnection - */ - struct GNUNET_CLIENT_TransmitHandle *th; - - /** - * Closure for all the handlers given by the client - */ - void *cls; - - /** - * Messages to send to the service, head. - */ - struct GNUNET_CADET_TransmitHandle *th_head; - - /** - * Messages to send to the service, tail. - */ - struct GNUNET_CADET_TransmitHandle *th_tail; - - /** - * chid of the next channel to create (to avoid reusing IDs often) - */ - CADET_ChannelNumber next_chid; - - /** - * Have we started the task to receive messages from the service - * yet? We do this after we send the 'CADET_LOCAL_CONNECT' message. - */ - int in_receive; - - /** - * Configuration given by the client, in case of reconnection - */ - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Time to the next reconnect in case one reconnect fails - */ - struct GNUNET_TIME_Relative reconnect_time; - - /** - * Task for trying to reconnect. - */ - GNUNET_SCHEDULER_TaskIdentifier reconnect_task; - - /** - * Callback for an info task (only one active at a time). - */ - union CadetInfoCB info_cb; - - /** - * Info callback closure for @c info_cb. - */ - void *info_cls; -}; - - -/** - * Description of a peer - */ -struct GNUNET_CADET_Peer -{ - /** - * ID of the peer in short form - */ - GNUNET_PEER_Id id; - - /** - * Channel this peer belongs to - */ - struct GNUNET_CADET_Channel *t; -}; - - -/** - * Opaque handle to a channel. - */ -struct GNUNET_CADET_Channel -{ - - /** - * DLL next - */ - struct GNUNET_CADET_Channel *next; - - /** - * DLL prev - */ - struct GNUNET_CADET_Channel *prev; - - /** - * Handle to the cadet this channel belongs to - */ - struct GNUNET_CADET_Handle *cadet; - - /** - * Local ID of the channel - */ - CADET_ChannelNumber chid; - - /** - * Port number. - */ - uint32_t port; - - /** - * Other end of the channel. - */ - GNUNET_PEER_Id peer; - - /** - * Any data the caller wants to put in here - */ - void *ctx; - - /** - * Size of packet queued in this channel - */ - unsigned int packet_size; - - /** - * Channel options: reliability, etc. - */ - enum GNUNET_CADET_ChannelOption options; - - /** - * Are we allowed to send to the service? - */ - int allow_send; - -}; - - -/** - * Implementation state for cadet's message queue. - */ -struct CadetMQState -{ - /** - * The current transmit handle, or NULL - * if no transmit is active. - */ - struct GNUNET_CADET_TransmitHandle *th; - - /** - * Channel to send the data over. - */ - struct GNUNET_CADET_Channel *channel; -}; - - -/******************************************************************************/ -/*********************** DECLARATIONS *************************/ -/******************************************************************************/ - -/** - * Function called to send a message to the service. - * "buf" will be NULL and "size" zero if the socket was closed for writing in - * the meantime. - * - * @param cls closure, the cadet handle - * @param size number of bytes available in buf - * @param buf where the callee should write the connect message - * @return number of bytes written to buf - */ -static size_t -send_callback (void *cls, size_t size, void *buf); - - -/******************************************************************************/ -/*********************** AUXILIARY FUNCTIONS *************************/ -/******************************************************************************/ - -/** - * Check if transmission is a payload packet. - * - * @param th Transmission handle. - * - * @return GNUNET_YES if it is a payload packet, - * GNUNET_NO if it is a cadet management packet. - */ -static int -th_is_payload (struct GNUNET_CADET_TransmitHandle *th) -{ - return (th->notify != NULL) ? GNUNET_YES : GNUNET_NO; -} - - -/** - * Check whether there is any message ready in the queue and find the size. - * - * @param h Cadet handle. - * - * @return The size of the first ready message in the queue, - * 0 if there is none. - */ -static size_t -message_ready_size (struct GNUNET_CADET_Handle *h) -{ - struct GNUNET_CADET_TransmitHandle *th; - struct GNUNET_CADET_Channel *ch; - - for (th = h->th_head; NULL != th; th = th->next) - { - ch = th->channel; - if (GNUNET_NO == th_is_payload (th)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "# message internal\n"); - return th->size; - } - if (GNUNET_YES == ch->allow_send) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "# message payload ok\n"); - return th->size; - } - } - return 0; -} - - -/** - * Get the channel handler for the channel specified by id from the given handle - * @param h Cadet handle - * @param chid ID of the wanted channel - * @return handle to the required channel or NULL if not found - */ -static struct GNUNET_CADET_Channel * -retrieve_channel (struct GNUNET_CADET_Handle *h, CADET_ChannelNumber chid) -{ - struct GNUNET_CADET_Channel *ch; - - ch = h->channels_head; - while (ch != NULL) - { - if (ch->chid == chid) - return ch; - ch = ch->next; - } - return NULL; -} - - -/** - * Create a new channel and insert it in the channel list of the cadet handle - * - * @param h Cadet handle - * @param chid Desired chid of the channel, 0 to assign one automatically. - * - * @return Handle to the created channel. - */ -static struct GNUNET_CADET_Channel * -create_channel (struct GNUNET_CADET_Handle *h, CADET_ChannelNumber chid) -{ - struct GNUNET_CADET_Channel *ch; - - ch = GNUNET_new (struct GNUNET_CADET_Channel); - GNUNET_CONTAINER_DLL_insert (h->channels_head, h->channels_tail, ch); - ch->cadet = h; - if (0 == chid) - { - ch->chid = h->next_chid; - while (NULL != retrieve_channel (h, h->next_chid)) - { - h->next_chid++; - h->next_chid &= ~GNUNET_CADET_LOCAL_CHANNEL_ID_SERV; - h->next_chid |= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI; - } - } - else - { - ch->chid = chid; - } - ch->allow_send = GNUNET_NO; - return ch; -} - - -/** - * Destroy the specified channel. - * - Destroys all peers, calling the disconnect callback on each if needed - * - Cancels all outgoing traffic for that channel, calling respective notifys - * - Calls cleaner if channel was inbound - * - Frees all memory used - * - * @param ch Pointer to the channel. - * @param call_cleaner Whether to call the cleaner handler. - * - * @return Handle to the required channel or NULL if not found. - */ -static void -destroy_channel (struct GNUNET_CADET_Channel *ch, int call_cleaner) -{ - struct GNUNET_CADET_Handle *h; - struct GNUNET_CADET_TransmitHandle *th; - struct GNUNET_CADET_TransmitHandle *next; - - LOG (GNUNET_ERROR_TYPE_DEBUG, " destroy_channel %X\n", ch->chid); - - if (NULL == ch) - { - GNUNET_break (0); - return; - } - h = ch->cadet; - - GNUNET_CONTAINER_DLL_remove (h->channels_head, h->channels_tail, ch); - - /* signal channel destruction */ - if ( (NULL != h->cleaner) && (0 != ch->peer) && (GNUNET_YES == call_cleaner) ) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " calling cleaner\n"); - h->cleaner (h->cls, ch, ch->ctx); - } - - /* check that clients did not leave messages behind in the queue */ - for (th = h->th_head; NULL != th; th = next) - { - next = th->next; - if (th->channel != ch) - continue; - /* Clients should have aborted their requests already. - * Management traffic should be ok, as clients can't cancel that. - * If the service crashed and we are reconnecting, it's ok. - */ - GNUNET_break (GNUNET_NO == th_is_payload (th) - || GNUNET_NO == h->in_receive); - GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th); - - /* clean up request */ - if (GNUNET_SCHEDULER_NO_TASK != th->timeout_task) - GNUNET_SCHEDULER_cancel (th->timeout_task); - GNUNET_free (th); - } - - /* if there are no more pending requests with cadet service, cancel active request */ - /* Note: this should be unnecessary... */ - if ((0 == message_ready_size (h)) && (NULL != h->th)) - { - GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); - h->th = NULL; - } - - if (0 != ch->peer) - GNUNET_PEER_change_rc (ch->peer, -1); - GNUNET_free (ch); - return; -} - - -/** - * Notify client that the transmission has timed out - * - * @param cls closure - * @param tc task context - */ -static void -timeout_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_CADET_TransmitHandle *th = cls; - struct GNUNET_CADET_Handle *cadet; - - cadet = th->channel->cadet; - GNUNET_CONTAINER_DLL_remove (cadet->th_head, cadet->th_tail, th); - th->channel->packet_size = 0; - if (GNUNET_YES == th_is_payload (th)) - th->notify (th->notify_cls, 0, NULL); - GNUNET_free (th); - if ((0 == message_ready_size (cadet)) && (NULL != cadet->th)) - { - /* nothing ready to transmit, no point in asking for transmission */ - GNUNET_CLIENT_notify_transmit_ready_cancel (cadet->th); - cadet->th = NULL; - } -} - - -/** - * Add a transmit handle to the transmission queue and set the - * timeout if needed. - * - * @param h cadet handle with the queue head and tail - * @param th handle to the packet to be transmitted - */ -static void -add_to_queue (struct GNUNET_CADET_Handle *h, - struct GNUNET_CADET_TransmitHandle *th) -{ - GNUNET_CONTAINER_DLL_insert_tail (h->th_head, h->th_tail, th); - if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us == th->timeout.abs_value_us) - return; - th->timeout_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining - (th->timeout), &timeout_transmission, th); -} - - -/** - * Auxiliary function to send an already constructed packet to the service. - * Takes care of creating a new queue element, copying the message and - * calling the tmt_rdy function if necessary. - * - * @param h cadet handle - * @param msg message to transmit - * @param channel channel this send is related to (NULL if N/A) - */ -static void -send_packet (struct GNUNET_CADET_Handle *h, - const struct GNUNET_MessageHeader *msg, - struct GNUNET_CADET_Channel *channel); - - -/** - * Send an ack on the channel to confirm the processing of a message. - * - * @param ch Channel on which to send the ACK. - */ -static void -send_ack (struct GNUNET_CADET_Channel *ch) -{ - struct GNUNET_CADET_LocalAck msg; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending ACK on channel %X\n", ch->chid); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK); - msg.header.size = htons (sizeof (msg)); - msg.channel_id = htonl (ch->chid); - - send_packet (ch->cadet, &msg.header, ch); - return; -} - - - -/** - * Reconnect callback: tries to reconnect again after a failer previous - * reconnecttion - * @param cls closure (cadet handle) - * @param tc task context - */ -static void -reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - - -/** - * Send a connect packet to the service with the applications and types - * requested by the user. - * - * @param h The cadet handle. - * - */ -static void -send_connect (struct GNUNET_CADET_Handle *h) -{ - size_t size; - - size = sizeof (struct GNUNET_CADET_ClientConnect); - size += h->n_ports * sizeof (uint32_t); - { - char buf[size] GNUNET_ALIGN; - struct GNUNET_CADET_ClientConnect *msg; - uint32_t *ports; - uint16_t i; - - /* build connection packet */ - msg = (struct GNUNET_CADET_ClientConnect *) buf; - msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT); - msg->header.size = htons (size); - ports = (uint32_t *) &msg[1]; - for (i = 0; i < h->n_ports; i++) - { - ports[i] = htonl (h->ports[i]); - LOG (GNUNET_ERROR_TYPE_DEBUG, " port %u\n", - h->ports[i]); - } - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Sending %lu bytes long message with %u ports\n", - ntohs (msg->header.size), h->n_ports); - send_packet (h, &msg->header, NULL); - } -} - - -/** - * Reconnect to the service, retransmit all infomation to try to restore the - * original state. - * - * @param h handle to the cadet - * - * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...) - */ -static int -do_reconnect (struct GNUNET_CADET_Handle *h) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n"); - LOG (GNUNET_ERROR_TYPE_DEBUG, "******* RECONNECT *******\n"); - LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n"); - LOG (GNUNET_ERROR_TYPE_DEBUG, "******** on %p *******\n", h); - LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n"); - - /* disconnect */ - if (NULL != h->th) - { - GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); - h->th = NULL; - } - if (NULL != h->client) - { - GNUNET_CLIENT_disconnect (h->client); - } - - /* connect again */ - h->client = GNUNET_CLIENT_connect ("cadet", h->cfg); - if (h->client == NULL) - { - h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time, - &reconnect_cbk, h); - h->reconnect_time = - GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS, - GNUNET_TIME_relative_multiply - (h->reconnect_time, 2)); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Next retry in %s\n", - GNUNET_STRINGS_relative_time_to_string (h->reconnect_time, - GNUNET_NO)); - GNUNET_break (0); - return GNUNET_NO; - } - else - { - h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS; - } - send_connect (h); - return GNUNET_YES; -} - -/** - * Reconnect callback: tries to reconnect again after a failer previous - * reconnecttion - * @param cls closure (cadet handle) - * @param tc task context - */ -static void -reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_CADET_Handle *h = cls; - - h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; - do_reconnect (h); -} - - -/** - * Reconnect to the service, retransmit all infomation to try to restore the - * original state. - * - * @param h handle to the cadet - * - * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...) - */ -static void -reconnect (struct GNUNET_CADET_Handle *h) -{ - struct GNUNET_CADET_Channel *ch; - struct GNUNET_CADET_Channel *next; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Requested RECONNECT, destroying all channels\n"); - h->in_receive = GNUNET_NO; - for (ch = h->channels_head; NULL != ch; ch = next) - { - next = ch->next; - destroy_channel (ch, GNUNET_YES); - } - if (GNUNET_SCHEDULER_NO_TASK == h->reconnect_task) - h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time, - &reconnect_cbk, h); -} - - -/******************************************************************************/ -/*********************** RECEIVE HANDLERS ****************************/ -/******************************************************************************/ - -/** - * Process the new channel notification and add it to the channels in the handle - * - * @param h The cadet handle - * @param msg A message with the details of the new incoming channel - */ -static void -process_channel_created (struct GNUNET_CADET_Handle *h, - const struct GNUNET_CADET_ChannelMessage *msg) -{ - struct GNUNET_CADET_Channel *ch; - CADET_ChannelNumber chid; - uint32_t port; - - chid = ntohl (msg->channel_id); - port = ntohl (msg->port); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating incoming channel %X:%u\n", chid, port); - if (chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV) - { - GNUNET_break (0); - return; - } - if (NULL != h->new_channel) - { - void *ctx; - - ch = create_channel (h, chid); - ch->allow_send = GNUNET_NO; - ch->peer = GNUNET_PEER_intern (&msg->peer); - ch->cadet = h; - ch->chid = chid; - ch->port = port; - ch->options = ntohl (msg->opt); - - LOG (GNUNET_ERROR_TYPE_DEBUG, " created channel %p\n", ch); - ctx = h->new_channel (h->cls, ch, &msg->peer, ch->port, ch->options); - if (NULL != ctx) - ch->ctx = ctx; - LOG (GNUNET_ERROR_TYPE_DEBUG, "User notified\n"); - } - else - { - struct GNUNET_CADET_ChannelMessage d_msg; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "No handler for incoming channels\n"); - - d_msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY); - d_msg.header.size = htons (sizeof (struct GNUNET_CADET_ChannelMessage)); - d_msg.channel_id = msg->channel_id; - memset (&d_msg.peer, 0, sizeof (struct GNUNET_PeerIdentity)); - d_msg.port = 0; - d_msg.opt = 0; - - send_packet (h, &d_msg.header, NULL); - } - return; -} - - -/** - * Process the channel destroy notification and free associated resources - * - * @param h The cadet handle - * @param msg A message with the details of the channel being destroyed - */ -static void -process_channel_destroy (struct GNUNET_CADET_Handle *h, - const struct GNUNET_CADET_ChannelMessage *msg) -{ - struct GNUNET_CADET_Channel *ch; - CADET_ChannelNumber chid; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel Destroy received from service\n"); - chid = ntohl (msg->channel_id); - ch = retrieve_channel (h, chid); - - if (NULL == ch) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "channel %X unknown\n", chid); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " destroying channel %X\n", ch->chid); - destroy_channel (ch, GNUNET_YES); -} - - -/** - * Process the incoming data packets, call appropriate handlers. - * - * @param h The cadet handle - * @param message A message encapsulating the data - */ -static void -process_incoming_data (struct GNUNET_CADET_Handle *h, - const struct GNUNET_MessageHeader *message) -{ - const struct GNUNET_MessageHeader *payload; - const struct GNUNET_CADET_MessageHandler *handler; - struct GNUNET_CADET_LocalData *dmsg; - struct GNUNET_CADET_Channel *ch; - size_t size; - unsigned int i; - uint16_t type; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a data message!\n"); - dmsg = (struct GNUNET_CADET_LocalData *) message; - ch = retrieve_channel (h, ntohl (dmsg->id)); - if (NULL == ch) - { - GNUNET_break (0); - return; - } - - payload = (struct GNUNET_MessageHeader *) &dmsg[1]; - LOG (GNUNET_ERROR_TYPE_DEBUG, " %s data on channel %s [%X]\n", - GM_f2s (ch->chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV), - GNUNET_i2s (GNUNET_PEER_resolve2 (ch->peer)), ntohl (dmsg->id)); - - size = ntohs (message->size); - LOG (GNUNET_ERROR_TYPE_DEBUG, " %u bytes\n", size); - - if (NULL == ch) - { - /* Channel was ignored/destroyed, probably service didn't get it yet */ - LOG (GNUNET_ERROR_TYPE_DEBUG, " ignored!\n"); - return; - } - type = ntohs (payload->type); - size = ntohs (payload->size); - LOG (GNUNET_ERROR_TYPE_DEBUG, " payload type %s\n", GM_m2s (type)); - for (i = 0; i < h->n_handlers; i++) - { - handler = &h->message_handlers[i]; - LOG (GNUNET_ERROR_TYPE_DEBUG, " checking handler for type %u\n", - handler->type); - if (handler->type == type) - { - if (GNUNET_OK != - handler->callback (h->cls, ch, &ch->ctx, payload)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "callback caused disconnection\n"); - GNUNET_CADET_channel_destroy (ch); - return; - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "callback completed successfully\n"); - return; - } - } - } -} - - -/** - * Process a local ACK message, enabling the client to send - * more data to the service. - * - * @param h Cadet handle. - * @param message Message itself. - */ -static void -process_ack (struct GNUNET_CADET_Handle *h, - const struct GNUNET_MessageHeader *message) -{ - struct GNUNET_CADET_LocalAck *msg; - struct GNUNET_CADET_Channel *ch; - CADET_ChannelNumber chid; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Got an ACK!\n"); - msg = (struct GNUNET_CADET_LocalAck *) message; - chid = ntohl (msg->channel_id); - ch = retrieve_channel (h, chid); - if (NULL == ch) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "ACK on unknown channel %X\n", chid); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X!\n", ch->chid); - ch->allow_send = GNUNET_YES; - if (NULL == h->th && 0 < ch->packet_size) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " tmt rdy was NULL, requesting!\n"); - h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, ch->packet_size, - GNUNET_TIME_UNIT_FOREVER_REL, - GNUNET_YES, &send_callback, h); - } -} - - -/* - * Process a local reply about info on all channels, pass info to the user. - * - * @param h Cadet handle. - * @param message Message itself. - */ -// static void -// process_get_channels (struct GNUNET_CADET_Handle *h, -// const struct GNUNET_MessageHeader *message) -// { -// struct GNUNET_CADET_LocalInfo *msg; -// -// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Get Channels messasge received\n"); -// -// if (NULL == h->channels_cb) -// { -// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " ignored\n"); -// return; -// } -// -// msg = (struct GNUNET_CADET_LocalInfo *) message; -// if (ntohs (message->size) != -// (sizeof (struct GNUNET_CADET_LocalInfo) + -// sizeof (struct GNUNET_PeerIdentity))) -// { -// GNUNET_break_op (0); -// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -// "Get channels message: size %hu - expected %u\n", -// ntohs (message->size), -// sizeof (struct GNUNET_CADET_LocalInfo)); -// return; -// } -// h->channels_cb (h->channels_cls, -// ntohl (msg->channel_id), -// &msg->owner, -// &msg->destination); -// } - - - -/* - * Process a local monitor_channel reply, pass info to the user. - * - * @param h Cadet handle. - * @param message Message itself. - */ -// static void -// process_show_channel (struct GNUNET_CADET_Handle *h, -// const struct GNUNET_MessageHeader *message) -// { -// struct GNUNET_CADET_LocalInfo *msg; -// size_t esize; -// -// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Show Channel messasge received\n"); -// -// if (NULL == h->channel_cb) -// { -// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " ignored\n"); -// return; -// } -// -// /* Verify message sanity */ -// msg = (struct GNUNET_CADET_LocalInfo *) message; -// esize = sizeof (struct GNUNET_CADET_LocalInfo); -// if (ntohs (message->size) != esize) -// { -// GNUNET_break_op (0); -// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -// "Show channel message: size %hu - expected %u\n", -// ntohs (message->size), -// esize); -// -// h->channel_cb (h->channel_cls, NULL, NULL); -// h->channel_cb = NULL; -// h->channel_cls = NULL; -// -// return; -// } -// -// h->channel_cb (h->channel_cls, -// &msg->destination, -// &msg->owner); -// } - - - -/** - * Process a local reply about info on all tunnels, pass info to the user. - * - * @param h Cadet handle. - * @param message Message itself. - */ -static void -process_get_peers (struct GNUNET_CADET_Handle *h, - const struct GNUNET_MessageHeader *message) -{ - struct GNUNET_CADET_LocalInfoPeer *msg; - uint16_t size; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Get Peer messasge received\n"); - - if (NULL == h->info_cb.peers_cb) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ignored\n"); - return; - } - - size = ntohs (message->size); - if (sizeof (struct GNUNET_CADET_LocalInfoPeer) > size) - { - h->info_cb.peers_cb (h->info_cls, NULL, -1, 0, 0); - h->info_cb.peers_cb = NULL; - h->info_cls = NULL; - return; - } - - msg = (struct GNUNET_CADET_LocalInfoPeer *) message; - h->info_cb.peers_cb (h->info_cls, &msg->destination, - (int) ntohs (msg->tunnel), - (unsigned int ) ntohs (msg->paths), - 0); -} - - -/** - * Process a local peer info reply, pass info to the user. - * - * @param h Cadet handle. - * @param message Message itself. - */ -static void -process_get_peer (struct GNUNET_CADET_Handle *h, - const struct GNUNET_MessageHeader *message) -{ - struct GNUNET_CADET_LocalInfoTunnel *msg; - size_t esize; - size_t msize; - unsigned int ch_n; - unsigned int c_n; - struct GNUNET_CADET_Hash *conns; - CADET_ChannelNumber *chns; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Get Tunnel messasge received\n"); - if (NULL == h->info_cb.tunnel_cb) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ignored\n"); - return; - } - - /* Verify message sanity */ - msg = (struct GNUNET_CADET_LocalInfoTunnel *) message; - msize = ntohs (message->size); - esize = sizeof (struct GNUNET_CADET_LocalInfoTunnel); - if (esize > msize) - { - GNUNET_break_op (0); - h->info_cb.tunnel_cb (h->info_cls, NULL, 0, 0, NULL, NULL, 0, 0); - goto clean_cls; - } - ch_n = ntohl (msg->channels); - c_n = ntohl (msg->connections); - esize += ch_n * sizeof (CADET_ChannelNumber); - esize += c_n * sizeof (struct GNUNET_CADET_Hash); - if (msize != esize) - { - GNUNET_break_op (0); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "m:%u, e: %u (%u ch, %u conn)\n", - msize, esize, ch_n, c_n); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%u (%u ch, %u conn)\n", - sizeof (struct GNUNET_CADET_LocalInfoTunnel), - sizeof (CADET_ChannelNumber), sizeof (struct GNUNET_HashCode)); - h->info_cb.tunnel_cb (h->info_cls, NULL, 0, 0, NULL, NULL, 0, 0); - goto clean_cls; - } - - /* Call Callback with tunnel info. */ - conns = (struct GNUNET_CADET_Hash *) &msg[1]; - chns = (CADET_ChannelNumber *) &conns[c_n]; - h->info_cb.tunnel_cb (h->info_cls, &msg->destination, - ch_n, c_n, chns, conns, - ntohs (msg->estate), ntohs (msg->cstate)); - - clean_cls: - h->info_cb.tunnel_cb = NULL; - h->info_cls = NULL; -} - - -/** - * Process a local reply about info on all tunnels, pass info to the user. - * - * @param h Cadet handle. - * @param message Message itself. - */ -static void -process_get_tunnels (struct GNUNET_CADET_Handle *h, - const struct GNUNET_MessageHeader *message) -{ - struct GNUNET_CADET_LocalInfoTunnel *msg; - uint16_t size; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Get Tunnels messasge received\n"); - - if (NULL == h->info_cb.tunnels_cb) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ignored\n"); - return; - } - - size = ntohs (message->size); - if (sizeof (struct GNUNET_CADET_LocalInfoTunnel) > size) - { - h->info_cb.tunnels_cb (h->info_cls, NULL, 0, 0, 0, 0); - h->info_cb.tunnels_cb = NULL; - h->info_cls = NULL; - return; - } - - msg = (struct GNUNET_CADET_LocalInfoTunnel *) message; - h->info_cb.tunnels_cb (h->info_cls, &msg->destination, - ntohl (msg->channels), ntohl (msg->connections), - ntohs (msg->estate), ntohs (msg->cstate)); - -} - - -/** - * Process a local tunnel info reply, pass info to the user. - * - * @param h Cadet handle. - * @param message Message itself. - */ -static void -process_get_tunnel (struct GNUNET_CADET_Handle *h, - const struct GNUNET_MessageHeader *message) -{ - struct GNUNET_CADET_LocalInfoTunnel *msg; - size_t esize; - size_t msize; - unsigned int ch_n; - unsigned int c_n; - struct GNUNET_CADET_Hash *conns; - CADET_ChannelNumber *chns; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Get Tunnel messasge received\n"); - if (NULL == h->info_cb.tunnel_cb) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ignored\n"); - return; - } - - /* Verify message sanity */ - msg = (struct GNUNET_CADET_LocalInfoTunnel *) message; - msize = ntohs (message->size); - esize = sizeof (struct GNUNET_CADET_LocalInfoTunnel); - if (esize > msize) - { - GNUNET_break_op (0); - h->info_cb.tunnel_cb (h->info_cls, NULL, 0, 0, NULL, NULL, 0, 0); - goto clean_cls; - } - ch_n = ntohl (msg->channels); - c_n = ntohl (msg->connections); - esize += ch_n * sizeof (CADET_ChannelNumber); - esize += c_n * sizeof (struct GNUNET_CADET_Hash); - if (msize != esize) - { - GNUNET_break_op (0); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "m:%u, e: %u (%u ch, %u conn)\n", - msize, esize, ch_n, c_n); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%u (%u ch, %u conn)\n", - sizeof (struct GNUNET_CADET_LocalInfoTunnel), - sizeof (CADET_ChannelNumber), sizeof (struct GNUNET_HashCode)); - h->info_cb.tunnel_cb (h->info_cls, NULL, 0, 0, NULL, NULL, 0, 0); - goto clean_cls; - } - - /* Call Callback with tunnel info. */ - conns = (struct GNUNET_CADET_Hash *) &msg[1]; - chns = (CADET_ChannelNumber *) &conns[c_n]; - h->info_cb.tunnel_cb (h->info_cls, &msg->destination, - ch_n, c_n, chns, conns, - ntohs (msg->estate), ntohs (msg->cstate)); - -clean_cls: - h->info_cb.tunnel_cb = NULL; - h->info_cls = NULL; -} - - -/** - * Function to process all messages received from the service - * - * @param cls closure - * @param msg message received, NULL on timeout or fatal error - */ -static void -msg_received (void *cls, const struct GNUNET_MessageHeader *msg) -{ - struct GNUNET_CADET_Handle *h = cls; - uint16_t type; - - if (msg == NULL) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Cadet service disconnected, reconnecting\n", h); - reconnect (h); - return; - } - type = ntohs (msg->type); - LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Received a message: %s\n", - GM_m2s (type)); - switch (type) - { - /* Notify of a new incoming channel */ - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE: - process_channel_created (h, (struct GNUNET_CADET_ChannelMessage *) msg); - break; - /* Notify of a channel disconnection */ - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: /* TODO separate(gid problem)*/ - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK: - process_channel_destroy (h, (struct GNUNET_CADET_ChannelMessage *) msg); - break; - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA: - process_incoming_data (h, msg); - break; - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK: - process_ack (h, msg); - break; -// case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNELS: -// process_get_channels (h, msg); -// break; -// case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL: -// process_show_channel (h, msg); -// break; - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS: - process_get_peers (h, msg); - break; - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER: - process_get_peer (h, msg); - break; - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS: - process_get_tunnels (h, msg); - break; - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL: - process_get_tunnel (h, msg); - break; -// case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL: -// process_show_channel (h, msg); -// break; - default: - /* We shouldn't get any other packages, log and ignore */ - LOG (GNUNET_ERROR_TYPE_WARNING, - "unsolicited message form service (type %s)\n", - GM_m2s (ntohs (msg->type))); - } - LOG (GNUNET_ERROR_TYPE_DEBUG, "message processed\n"); - if (GNUNET_YES == h->in_receive) - { - GNUNET_CLIENT_receive (h->client, &msg_received, h, - GNUNET_TIME_UNIT_FOREVER_REL); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "in receive off, not calling CLIENT_receive\n"); - } -} - - -/******************************************************************************/ -/************************ SEND FUNCTIONS ****************************/ -/******************************************************************************/ - -/** - * Function called to send a message to the service. - * "buf" will be NULL and "size" zero if the socket was closed for writing in - * the meantime. - * - * @param cls closure, the cadet handle - * @param size number of bytes available in buf - * @param buf where the callee should write the connect message - * @return number of bytes written to buf - */ -static size_t -send_callback (void *cls, size_t size, void *buf) -{ - struct GNUNET_CADET_Handle *h = cls; - struct GNUNET_CADET_TransmitHandle *th; - struct GNUNET_CADET_TransmitHandle *next; - struct GNUNET_CADET_Channel *ch; - char *cbuf = buf; - size_t tsize; - size_t psize; - size_t nsize; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); - LOG (GNUNET_ERROR_TYPE_DEBUG, "# Send packet() Buffer %u\n", size); - if ((0 == size) || (NULL == buf)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "# Received NULL send callback on %p\n", h); - reconnect (h); - h->th = NULL; - return 0; - } - tsize = 0; - next = h->th_head; - nsize = message_ready_size (h); - while ((NULL != (th = next)) && (0 < nsize) && (size >= nsize)) - { - ch = th->channel; - if (GNUNET_YES == th_is_payload (th)) - { - struct GNUNET_CADET_LocalData *dmsg; - struct GNUNET_MessageHeader *mh; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "# payload\n"); - if (GNUNET_NO == ch->allow_send) - { - /* This channel is not ready to transmit yet, try next message */ - next = th->next; - continue; - } - ch->packet_size = 0; - GNUNET_assert (size >= th->size); - dmsg = (struct GNUNET_CADET_LocalData *) cbuf; - mh = (struct GNUNET_MessageHeader *) &dmsg[1]; - psize = th->notify (th->notify_cls, - size - sizeof (struct GNUNET_CADET_LocalData), - mh); - if (psize > 0) - { - psize += sizeof (struct GNUNET_CADET_LocalData); - GNUNET_assert (size >= psize); - dmsg->header.size = htons (psize); - dmsg->id = htonl (ch->chid); - dmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA); - LOG (GNUNET_ERROR_TYPE_DEBUG, "# payload type %s\n", - GM_m2s (ntohs (mh->type))); - ch->allow_send = GNUNET_NO; - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "# callback returned size 0, " - "application canceled transmission\n"); - } - } - else - { - struct GNUNET_MessageHeader *mh = (struct GNUNET_MessageHeader *) &th[1]; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "# cadet internal traffic, type %s\n", - GM_m2s (ntohs (mh->type))); - memcpy (cbuf, &th[1], th->size); - psize = th->size; - } - if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (th->timeout_task); - GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th); - GNUNET_free (th); - next = h->th_head; - nsize = message_ready_size (h); - cbuf += psize; - size -= psize; - tsize += psize; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, "# total size: %u\n", tsize); - h->th = NULL; - size = message_ready_size (h); - if (0 != size) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "# next size: %u\n", size); - h->th = - GNUNET_CLIENT_notify_transmit_ready (h->client, size, - GNUNET_TIME_UNIT_FOREVER_REL, - GNUNET_YES, &send_callback, h); - } - else - { - if (NULL != h->th_head) - LOG (GNUNET_ERROR_TYPE_DEBUG, "# can't transmit any more\n"); - else - LOG (GNUNET_ERROR_TYPE_DEBUG, "# nothing left to transmit\n"); - } - if (GNUNET_NO == h->in_receive) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "# start receiving from service\n"); - h->in_receive = GNUNET_YES; - GNUNET_CLIENT_receive (h->client, &msg_received, h, - GNUNET_TIME_UNIT_FOREVER_REL); - } - LOG (GNUNET_ERROR_TYPE_DEBUG, "# Send packet() END\n"); - return tsize; -} - - -/** - * Auxiliary function to send an already constructed packet to the service. - * Takes care of creating a new queue element, copying the message and - * calling the tmt_rdy function if necessary. - * - * @param h cadet handle - * @param msg message to transmit - * @param channel channel this send is related to (NULL if N/A) - */ -static void -send_packet (struct GNUNET_CADET_Handle *h, - const struct GNUNET_MessageHeader *msg, - struct GNUNET_CADET_Channel *channel) -{ - struct GNUNET_CADET_TransmitHandle *th; - size_t msize; - - LOG (GNUNET_ERROR_TYPE_DEBUG, " Sending message to service: %s\n", - GM_m2s(ntohs(msg->type))); - msize = ntohs (msg->size); - th = GNUNET_malloc (sizeof (struct GNUNET_CADET_TransmitHandle) + msize); - th->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; - th->size = msize; - th->channel = channel; - memcpy (&th[1], msg, msize); - add_to_queue (h, th); - LOG (GNUNET_ERROR_TYPE_DEBUG, " queued\n"); - if (NULL != h->th) - return; - LOG (GNUNET_ERROR_TYPE_DEBUG, " calling ntfy tmt rdy for %u bytes\n", msize); - h->th = - GNUNET_CLIENT_notify_transmit_ready (h->client, msize, - GNUNET_TIME_UNIT_FOREVER_REL, - GNUNET_YES, &send_callback, h); -} - - -/******************************************************************************/ -/********************** API CALL DEFINITIONS *************************/ -/******************************************************************************/ - -struct GNUNET_CADET_Handle * -GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, void *cls, - GNUNET_CADET_InboundChannelNotificationHandler new_channel, - GNUNET_CADET_ChannelEndHandler cleaner, - const struct GNUNET_CADET_MessageHandler *handlers, - const uint32_t *ports) -{ - struct GNUNET_CADET_Handle *h; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_CADET_connect()\n"); - h = GNUNET_new (struct GNUNET_CADET_Handle); - LOG (GNUNET_ERROR_TYPE_DEBUG, " addr %p\n", h); - h->cfg = cfg; - h->new_channel = new_channel; - h->cleaner = cleaner; - h->client = GNUNET_CLIENT_connect ("cadet", cfg); - if (h->client == NULL) - { - GNUNET_break (0); - GNUNET_free (h); - return NULL; - } - h->cls = cls; - h->message_handlers = handlers; - h->ports = ports; - h->next_chid = GNUNET_CADET_LOCAL_CHANNEL_ID_CLI; - h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS; - h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; - - if (NULL != ports && ports[0] != 0 && NULL == new_channel) - { - GNUNET_break (0); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "no new channel handler given, ports parameter is useless!!\n"); - } - if ((NULL == ports || ports[0] == 0) && NULL != new_channel) - { - GNUNET_break (0); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "no ports given, new channel handler will never be called!!\n"); - } - /* count handlers */ - for (h->n_handlers = 0; - handlers && handlers[h->n_handlers].type; - h->n_handlers++) ; - for (h->n_ports = 0; - ports && ports[h->n_ports]; - h->n_ports++) ; - send_connect (h); - LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_CADET_connect() END\n"); - return h; -} - - -void -GNUNET_CADET_disconnect (struct GNUNET_CADET_Handle *handle) -{ - struct GNUNET_CADET_Channel *ch; - struct GNUNET_CADET_Channel *aux; - struct GNUNET_CADET_TransmitHandle *th; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "CADET DISCONNECT\n"); - - ch = handle->channels_head; - while (NULL != ch) - { - aux = ch->next; - if (ch->chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV) - { - GNUNET_break (0); - LOG (GNUNET_ERROR_TYPE_DEBUG, "channel %X not destroyed\n", ch->chid); - } - destroy_channel (ch, GNUNET_YES); - ch = aux; - } - while ( (th = handle->th_head) != NULL) - { - struct GNUNET_MessageHeader *msg; - - /* Make sure it is an allowed packet (everything else should have been - * already canceled). - */ - GNUNET_break (GNUNET_NO == th_is_payload (th)); - msg = (struct GNUNET_MessageHeader *) &th[1]; - switch (ntohs(msg->type)) - { - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT: - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE: - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNELS: - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL: - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER: - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS: - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL: - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS: - break; - default: - GNUNET_break (0); - LOG (GNUNET_ERROR_TYPE_ERROR, "unexpected msg %u\n", - ntohs(msg->type)); - } - - GNUNET_CONTAINER_DLL_remove (handle->th_head, handle->th_tail, th); - GNUNET_free (th); - } - - if (NULL != handle->th) - { - GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th); - handle->th = NULL; - } - if (NULL != handle->client) - { - GNUNET_CLIENT_disconnect (handle->client); - handle->client = NULL; - } - if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task) - { - GNUNET_SCHEDULER_cancel(handle->reconnect_task); - handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; - } - GNUNET_free (handle); -} - - -/** - * Create a new channel towards a remote peer. - * - * If the destination port is not open by any peer or the destination peer - * does not accept the channel, #GNUNET_CADET_ChannelEndHandler will be called - * for this channel. - * - * @param h cadet handle - * @param channel_ctx client's channel context to associate with the channel - * @param peer peer identity the channel should go to - * @param port Port number. - * @param options CadetOption flag field, with all desired option bits set to 1. - * - * @return handle to the channel - */ -struct GNUNET_CADET_Channel * -GNUNET_CADET_channel_create (struct GNUNET_CADET_Handle *h, - void *channel_ctx, - const struct GNUNET_PeerIdentity *peer, - uint32_t port, - enum GNUNET_CADET_ChannelOption options) -{ - struct GNUNET_CADET_Channel *ch; - struct GNUNET_CADET_ChannelMessage msg; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Creating new channel to %s:%u\n", - GNUNET_i2s (peer), port); - ch = create_channel (h, 0); - LOG (GNUNET_ERROR_TYPE_DEBUG, " at %p\n", ch); - LOG (GNUNET_ERROR_TYPE_DEBUG, " number %X\n", ch->chid); - ch->ctx = channel_ctx; - ch->peer = GNUNET_PEER_intern (peer); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE); - msg.header.size = htons (sizeof (struct GNUNET_CADET_ChannelMessage)); - msg.channel_id = htonl (ch->chid); - msg.port = htonl (port); - msg.peer = *peer; - msg.opt = htonl (options); - ch->allow_send = 0; - send_packet (h, &msg.header, ch); - return ch; -} - - -void -GNUNET_CADET_channel_destroy (struct GNUNET_CADET_Channel *channel) -{ - struct GNUNET_CADET_Handle *h; - struct GNUNET_CADET_ChannelMessage msg; - struct GNUNET_CADET_TransmitHandle *th; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying channel\n"); - h = channel->cadet; - - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY); - msg.header.size = htons (sizeof (struct GNUNET_CADET_ChannelMessage)); - msg.channel_id = htonl (channel->chid); - memset (&msg.peer, 0, sizeof (struct GNUNET_PeerIdentity)); - msg.port = 0; - msg.opt = 0; - th = h->th_head; - while (th != NULL) - { - struct GNUNET_CADET_TransmitHandle *aux; - if (th->channel == channel) - { - aux = th->next; - /* FIXME call the handler? */ - if (GNUNET_YES == th_is_payload (th)) - th->notify (th->notify_cls, 0, NULL); - GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th); - GNUNET_free (th); - th = aux; - } - else - th = th->next; - } - - destroy_channel (channel, GNUNET_YES); - send_packet (h, &msg.header, NULL); -} - - -/** - * Get information about a channel. - * - * @param channel Channel handle. - * @param option Query (GNUNET_CADET_OPTION_*). - * @param ... dependant on option, currently not used - * - * @return Union with an answer to the query. - */ -const union GNUNET_CADET_ChannelInfo * -GNUNET_CADET_channel_get_info (struct GNUNET_CADET_Channel *channel, - enum GNUNET_CADET_ChannelOption option, ...) -{ - static int bool_flag; - const union GNUNET_CADET_ChannelInfo *ret; - - switch (option) - { - case GNUNET_CADET_OPTION_NOBUFFER: - case GNUNET_CADET_OPTION_RELIABLE: - case GNUNET_CADET_OPTION_OOORDER: - if (0 != (option & channel->options)) - bool_flag = GNUNET_YES; - else - bool_flag = GNUNET_NO; - ret = (const union GNUNET_CADET_ChannelInfo *) &bool_flag; - break; - case GNUNET_CADET_OPTION_PEER: - ret = (const union GNUNET_CADET_ChannelInfo *) GNUNET_PEER_resolve2 (channel->peer); - break; - default: - GNUNET_break (0); - return NULL; - } - - return ret; -} - -struct GNUNET_CADET_TransmitHandle * -GNUNET_CADET_notify_transmit_ready (struct GNUNET_CADET_Channel *channel, int cork, - struct GNUNET_TIME_Relative maxdelay, - size_t notify_size, - GNUNET_CONNECTION_TransmitReadyNotify notify, - void *notify_cls) -{ - struct GNUNET_CADET_TransmitHandle *th; - - GNUNET_assert (NULL != channel); - LOG (GNUNET_ERROR_TYPE_DEBUG, "CADET NOTIFY TRANSMIT READY\n"); - LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X\n", channel->chid); - LOG (GNUNET_ERROR_TYPE_DEBUG, " allow_send %d\n", channel->allow_send); - if (channel->chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV) - LOG (GNUNET_ERROR_TYPE_DEBUG, " to origin\n"); - else - LOG (GNUNET_ERROR_TYPE_DEBUG, " to destination\n"); - LOG (GNUNET_ERROR_TYPE_DEBUG, " payload size %u\n", notify_size); - GNUNET_assert (NULL != notify); - GNUNET_assert (0 == channel->packet_size); // Only one data packet allowed - th = GNUNET_new (struct GNUNET_CADET_TransmitHandle); - th->channel = channel; - th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay); - th->size = notify_size + sizeof (struct GNUNET_CADET_LocalData); - channel->packet_size = th->size; - LOG (GNUNET_ERROR_TYPE_DEBUG, " total size %u\n", th->size); - th->notify = notify; - th->notify_cls = notify_cls; - add_to_queue (channel->cadet, th); - if (NULL != channel->cadet->th) - return th; - if (GNUNET_NO == channel->allow_send) - return th; - LOG (GNUNET_ERROR_TYPE_DEBUG, " call client notify tmt rdy\n"); - channel->cadet->th = - GNUNET_CLIENT_notify_transmit_ready (channel->cadet->client, th->size, - GNUNET_TIME_UNIT_FOREVER_REL, - GNUNET_YES, &send_callback, - channel->cadet); - LOG (GNUNET_ERROR_TYPE_DEBUG, "CADET NOTIFY TRANSMIT READY END\n"); - return th; -} - - -void -GNUNET_CADET_notify_transmit_ready_cancel (struct GNUNET_CADET_TransmitHandle *th) -{ - struct GNUNET_CADET_Handle *cadet; - - th->channel->packet_size = 0; - cadet = th->channel->cadet; - if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (th->timeout_task); - GNUNET_CONTAINER_DLL_remove (cadet->th_head, cadet->th_tail, th); - GNUNET_free (th); - if ((0 == message_ready_size (cadet)) && (NULL != cadet->th)) - { - /* queue empty, no point in asking for transmission */ - GNUNET_CLIENT_notify_transmit_ready_cancel (cadet->th); - cadet->th = NULL; - } -} - - -void -GNUNET_CADET_receive_done (struct GNUNET_CADET_Channel *channel) -{ - send_ack (channel); -} - - -static void -send_info_request (struct GNUNET_CADET_Handle *h, uint16_t type) -{ - struct GNUNET_MessageHeader msg; - - msg.size = htons (sizeof (msg)); - msg.type = htons (type); - send_packet (h, &msg, NULL); -} - - -/** - * Request information about peers known to the running cadet service. - * The callback will be called for every peer known to the service. - * Only one info request (of any kind) can be active at once. - * - * - * WARNING: unstable API, likely to change in the future! - * - * @param h Handle to the cadet peer. - * @param callback Function to call with the requested data. - * @param callback_cls Closure for @c callback. - * - * @return #GNUNET_OK / #GNUNET_SYSERR - */ -int -GNUNET_CADET_get_peers (struct GNUNET_CADET_Handle *h, - GNUNET_CADET_PeersCB callback, - void *callback_cls) -{ - if (NULL != h->info_cb.peers_cb) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - send_info_request (h, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS); - h->info_cb.peers_cb = callback; - h->info_cls = callback_cls; - return GNUNET_OK; -} - - -/** - * Cancel a peer info request. The callback will not be called (anymore). - * - * WARNING: unstable API, likely to change in the future! - * - * @param h Cadet handle. - * - * @return Closure given to GNUNET_CADET_get_peers. - */ -void * -GNUNET_CADET_get_peers_cancel (struct GNUNET_CADET_Handle *h) -{ - void *cls; - - cls = h->info_cls; - h->info_cb.peers_cb = NULL; - h->info_cls = NULL; - return cls; -} - - -/** - * Request information about a peer known to the running cadet peer. - * The callback will be called for the tunnel once. - * Only one info request (of any kind) can be active at once. - * - * WARNING: unstable API, likely to change in the future! - * - * @param h Handle to the cadet peer. - * @param id Peer whose tunnel to examine. - * @param callback Function to call with the requested data. - * @param callback_cls Closure for @c callback. - * - * @return #GNUNET_OK / #GNUNET_SYSERR - */ -int -GNUNET_CADET_get_peer (struct GNUNET_CADET_Handle *h, - const struct GNUNET_PeerIdentity *id, - GNUNET_CADET_PeerCB callback, - void *callback_cls) -{ - struct GNUNET_CADET_LocalInfo msg; - - if (NULL != h->info_cb.peer_cb) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - memset (&msg, 0, sizeof (msg)); - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER); - msg.peer = *id; - send_packet (h, &msg.header, NULL); - h->info_cb.peer_cb = callback; - h->info_cls = callback_cls; - return GNUNET_OK; -} - - -/** - * Request information about tunnels of the running cadet peer. - * The callback will be called for every tunnel of the service. - * Only one info request (of any kind) can be active at once. - * - * WARNING: unstable API, likely to change in the future! - * - * @param h Handle to the cadet peer. - * @param callback Function to call with the requested data. - * @param callback_cls Closure for @c callback. - * - * @return #GNUNET_OK / #GNUNET_SYSERR - */ -int -GNUNET_CADET_get_tunnels (struct GNUNET_CADET_Handle *h, - GNUNET_CADET_TunnelsCB callback, - void *callback_cls) -{ - if (NULL != h->info_cb.tunnels_cb) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - send_info_request (h, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS); - h->info_cb.tunnels_cb = callback; - h->info_cls = callback_cls; - return GNUNET_OK; -} - - -/** - * Cancel a monitor request. The monitor callback will not be called. - * - * @param h Cadet handle. - * - * @return Closure given to GNUNET_CADET_get_tunnels. - */ -void * -GNUNET_CADET_get_tunnels_cancel (struct GNUNET_CADET_Handle *h) -{ - void *cls; - - h->info_cb.tunnels_cb = NULL; - cls = h->info_cls; - h->info_cls = NULL; - - return cls; -} - - - -/** - * Request information about a tunnel of the running cadet peer. - * The callback will be called for the tunnel once. - * Only one info request (of any kind) can be active at once. - * - * WARNING: unstable API, likely to change in the future! - * - * @param h Handle to the cadet peer. - * @param id Peer whose tunnel to examine. - * @param callback Function to call with the requested data. - * @param callback_cls Closure for @c callback. - * - * @return #GNUNET_OK / #GNUNET_SYSERR - */ -int -GNUNET_CADET_get_tunnel (struct GNUNET_CADET_Handle *h, - const struct GNUNET_PeerIdentity *id, - GNUNET_CADET_TunnelCB callback, - void *callback_cls) -{ - struct GNUNET_CADET_LocalInfo msg; - - if (NULL != h->info_cb.tunnel_cb) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - memset (&msg, 0, sizeof (msg)); - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL); - msg.peer = *id; - send_packet (h, &msg.header, NULL); - h->info_cb.tunnel_cb = callback; - h->info_cls = callback_cls; - return GNUNET_OK; -} - - -/** - * Request information about a specific channel of the running cadet peer. - * - * WARNING: unstable API, likely to change in the future! - * FIXME Add destination option. - * - * @param h Handle to the cadet peer. - * @param initiator ID of the owner of the channel. - * @param channel_number Channel number. - * @param callback Function to call with the requested data. - * @param callback_cls Closure for @c callback. - * - * @return #GNUNET_OK / #GNUNET_SYSERR - */ -int -GNUNET_CADET_show_channel (struct GNUNET_CADET_Handle *h, - struct GNUNET_PeerIdentity *initiator, - unsigned int channel_number, - GNUNET_CADET_ChannelCB callback, - void *callback_cls) -{ - struct GNUNET_CADET_LocalInfo msg; - - if (NULL != h->info_cb.channel_cb) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL); - msg.peer = *initiator; - msg.channel_id = htonl (channel_number); -// msg.reserved = 0; - send_packet (h, &msg.header, NULL); - h->info_cb.channel_cb = callback; - h->info_cls = callback_cls; - return GNUNET_OK; -} - - -/** - * Function called to notify a client about the connection - * begin ready to queue more data. "buf" will be - * NULL and "size" zero if the connection 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 -cadet_mq_ntr (void *cls, size_t size, - void *buf) -{ - struct GNUNET_MQ_Handle *mq = cls; - struct CadetMQState *state = GNUNET_MQ_impl_state (mq); - const struct GNUNET_MessageHeader *msg = GNUNET_MQ_impl_current (mq); - uint16_t msize; - - state->th = NULL; - if (NULL == buf) - { - GNUNET_MQ_inject_error (mq, GNUNET_MQ_ERROR_WRITE); - return 0; - } - msize = ntohs (msg->size); - GNUNET_assert (msize <= size); - memcpy (buf, msg, msize); - GNUNET_MQ_impl_send_continue (mq); - return msize; -} - - -/** - * Signature of functions implementing the - * sending functionality of a message queue. - * - * @param mq the message queue - * @param msg the message to send - * @param impl_state state of the implementation - */ -static void -cadet_mq_send_impl (struct GNUNET_MQ_Handle *mq, - const struct GNUNET_MessageHeader *msg, void *impl_state) -{ - struct CadetMQState *state = impl_state; - - GNUNET_assert (NULL == state->th); - state->th = - GNUNET_CADET_notify_transmit_ready (state->channel, - /* FIXME: add option for corking */ - GNUNET_NO, - GNUNET_TIME_UNIT_FOREVER_REL, - ntohs (msg->size), - cadet_mq_ntr, mq); - -} - - -/** - * Signature of functions implementing the - * destruction of a message queue. - * Implementations must not free 'mq', but should - * take care of 'impl_state'. - * - * @param mq the message queue to destroy - * @param impl_state state of the implementation - */ -static void -cadet_mq_destroy_impl (struct GNUNET_MQ_Handle *mq, void *impl_state) -{ - struct CadetMQState *state = impl_state; - - if (NULL != state->th) - GNUNET_CADET_notify_transmit_ready_cancel (state->th); - - GNUNET_free (state); -} - - -/** - * Create a message queue for a cadet channel. - * The message queue can only be used to transmit messages, - * not to receive them. - * - * @param channel the channel to create the message qeue for - * @return a message queue to messages over the channel - */ -struct GNUNET_MQ_Handle * -GNUNET_CADET_mq_create (struct GNUNET_CADET_Channel *channel) -{ - struct GNUNET_MQ_Handle *mq; - struct CadetMQState *state; - - state = GNUNET_new (struct CadetMQState); - state->channel = channel; - - mq = GNUNET_MQ_queue_for_callbacks (cadet_mq_send_impl, - cadet_mq_destroy_impl, - NULL, /* FIXME: cancel impl. */ - state, - NULL, /* no msg handlers */ - NULL, /* no err handlers */ - NULL); /* no handler cls */ - return mq; -} - diff --git a/src/mesh/cadet_common.c b/src/mesh/cadet_common.c deleted file mode 100644 index 855e9e20c..000000000 --- a/src/mesh/cadet_common.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2012 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 cadet/cadet_common.c - * @brief CADET helper functions - * @author Bartlomiej Polot - */ - -#include "cadet.h" - -/** - * @brief Translate a fwd variable into a string representation, for logging. - * - * @param fwd Is FWD? (#GNUNET_YES or #GNUNET_NO) - * - * @return String representing FWD or BCK. - */ -char * -GM_f2s (int fwd) -{ - if (GNUNET_YES == fwd) - { - return "FWD"; - } - else if (GNUNET_NO == fwd) - { - return "BCK"; - } - else - { - /* Not an error, can happen with CONNECTION_BROKEN messages. */ - return ""; - } -} - -int -GM_is_pid_bigger (uint32_t bigger, uint32_t smaller) -{ - return (GNUNET_YES == PID_OVERFLOW (smaller, bigger) || - (bigger > smaller && GNUNET_NO == PID_OVERFLOW (bigger, smaller))); -} - - -uint32_t -GM_max_pid (uint32_t a, uint32_t b) -{ - if (GM_is_pid_bigger(a, b)) - return a; - return b; -} - - -uint32_t -GM_min_pid (uint32_t a, uint32_t b) -{ - if (GM_is_pid_bigger(a, b)) - return b; - return a; -} - - -const struct GNUNET_HashCode * -GM_h2hc (const struct GNUNET_CADET_Hash *id) -{ - static struct GNUNET_HashCode hc; - memcpy (&hc, id, sizeof (*id)); - - return &hc; -} - - -const char * -GM_h2s (const struct GNUNET_CADET_Hash *id) -{ - static char s[53]; - - memcpy (s, GNUNET_h2s_full (GM_h2hc (id)), 52); - s[52] = '\0'; - - return s; -} - - -#if !defined(GNUNET_CULL_LOGGING) -const char * -GM_m2s (uint16_t m) -{ - static char buf[32]; - const char *t; - - switch (m) - { - /** - * Request the creation of a path - */ - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE: - t = "CONNECTION_CREATE"; - break; - - /** - * Request the modification of an existing path - */ - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK: - t = "CONNECTION_ACK"; - break; - - /** - * Notify that a connection of a path is no longer valid - */ - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN: - t = "CONNECTION_BROKEN"; - break; - - /** - * At some point, the route will spontaneously change - */ - case GNUNET_MESSAGE_TYPE_CADET_PATH_CHANGED: - t = "PATH_CHANGED"; - break; - - /** - * Transport payload data. - */ - case GNUNET_MESSAGE_TYPE_CADET_DATA: - t = "DATA"; - break; - - /** - * Confirm receipt of payload data. - */ - case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK: - t = "DATA_ACK"; - break; - - /** - * Key exchange encapsulation. - */ - case GNUNET_MESSAGE_TYPE_CADET_KX: - t = "KX"; - break; - - /** - * New ephemeral key. - */ - case GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL: - t = "KX_EPHEMERAL"; - break; - - /** - * Challenge to test peer's session key. - */ - case GNUNET_MESSAGE_TYPE_CADET_KX_PING: - t = "KX_PING"; - break; - - /** - * Answer to session key challenge. - */ - case GNUNET_MESSAGE_TYPE_CADET_KX_PONG: - t = "KX_PONG"; - break; - - /** - * Request the destuction of a path - */ - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY: - t = "CONNECTION_DESTROY"; - break; - - /** - * ACK for a data packet. - */ - case GNUNET_MESSAGE_TYPE_CADET_ACK: - t = "ACK"; - break; - - /** - * POLL for ACK. - */ - case GNUNET_MESSAGE_TYPE_CADET_POLL: - t = "POLL"; - break; - - /** - * Announce origin is still alive. - */ - case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE: - t = "KEEPALIVE"; - break; - - /** - * Connect to the cadet service, specifying subscriptions - */ - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT: - t = "LOCAL_CONNECT"; - break; - - /** - * Ask the cadet service to create a new tunnel - */ - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE: - t = "CHANNEL_CREATE"; - break; - - /** - * Ask the cadet service to destroy a tunnel - */ - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: - t = "CHANNEL_DESTROY"; - break; - - /** - * Confirm the creation of a channel. - */ - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK: - t = "CHANNEL_ACK"; - break; - - /** - * Confirm the creation of a channel. - */ - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK: - t = "CHANNEL_NACK"; - break; - - /** - * Encrypted payload. - */ - case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED: - t = "ENCRYPTED"; - break; - - /** - * Local payload traffic - */ - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA: - t = "LOCAL_DATA"; - break; - - /** - * Local ACK for data. - */ - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK: - t = "LOCAL_ACK"; - break; - - /** - * Local monitoring of channels. - */ - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNELS: - t = "LOCAL_INFO_CHANNELS"; - break; - - /** - * Local monitoring of a channel. - */ - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL: - t = "LOCAL_INFO_CHANNEL"; - break; - - /** - * Local monitoring of service. - */ - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS: - t = "LOCAL_INFO_TUNNELS"; - break; - - /** - * Local monitoring of service. - */ - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL: - t = "LOCAL_INFO_TUNNEL"; - break; - - /** - * Local information about all connections of service. - */ - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CONNECTIONS: - t = "LOCAL_INFO_CONNECTIONS"; - break; - - /** - * Local information of service about a specific connection. - */ - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CONNECTION: - t = "LOCAL_INFO_CONNECTION"; - break; - - /** - * Local information about all peers known to the service. - */ - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS: - t = "LOCAL_INFO_PEERS"; - break; - - /** - * Local information of service about a specific peer. - */ - case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER: - t = "LOCAL_INFO_PEER"; - break; - - /** - * Traffic (net-cat style) used by the Command Line Interface. - */ - case GNUNET_MESSAGE_TYPE_CADET_CLI: - t = "CLI"; - break; - - /** - * 640kb should be enough for everybody - */ - case 299: - t = "RESERVE_END"; - break; - - default: - sprintf(buf, "%u (UNKNOWN TYPE)", m); - return buf; - } - sprintf(buf, "{%18s}", t); - return buf; -} -#else -const char * -GM_m2s (uint16_t m) -{ - return ""; -} -#endif diff --git a/src/mesh/cadet_path.c b/src/mesh/cadet_path.c deleted file mode 100644 index 0a97e73ef..000000000 --- a/src/mesh/cadet_path.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2001 - 2013 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 cadet/cadet_path.c - * @brief Path handling functions - * @author Bartlomiej Polot - */ - -#include "cadet.h" -#include "cadet_path.h" -#include "gnunet-service-cadet_peer.h" - -/** - * @brief Destroy a path after some time has past. - * - * If the path is returned from DHT again after a while, try again. - * - * @param cls Closure (path to destroy). - * @param tc Task context. - */ -static void -path_destroy_delayed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct CadetPeerPath *path = cls; - struct CadetPeer *peer; - - path->path_delete = GNUNET_SCHEDULER_NO_TASK; - peer = GMP_get_short (path->peers[path->length - 1]); - GMP_remove_path (peer, path); -} - - -/** - * Create a new path - * - * @param length How many hops will the path have. - * - * @return A newly allocated path with a peer array of the specified length. - */ -struct CadetPeerPath * -path_new (unsigned int length) -{ - struct CadetPeerPath *p; - - p = GNUNET_new (struct CadetPeerPath); - if (length > 0) - { - p->length = length; - p->peers = GNUNET_malloc (length * sizeof (GNUNET_PEER_Id)); - } - return p; -} - - -/** - * Invert the path - * - * @param path the path to invert - */ -void -path_invert (struct CadetPeerPath *path) -{ - GNUNET_PEER_Id aux; - unsigned int i; - - for (i = 0; i < path->length / 2; i++) - { - aux = path->peers[i]; - path->peers[i] = path->peers[path->length - i - 1]; - path->peers[path->length - i - 1] = aux; - } -} - - -/** - * Duplicate a path, incrementing short peer's rc. - * - * @param path The path to duplicate. - */ -struct CadetPeerPath * -path_duplicate (const struct CadetPeerPath *path) -{ - struct CadetPeerPath *aux; - unsigned int i; - - aux = path_new (path->length); - memcpy (aux->peers, path->peers, path->length * sizeof (GNUNET_PEER_Id)); - for (i = 0; i < aux->length; i++) - GNUNET_PEER_change_rc (aux->peers[i], 1); - return aux; -} - - -/** - * Get the length of a path. - * - * @param path The path to measure, with the local peer at any point of it. - * - * @return Number of hops to reach destination. - * UINT_MAX in case the peer is not in the path. - */ -unsigned int -path_get_length (struct CadetPeerPath *path) -{ - if (NULL == path) - return UINT_MAX; - return path->length; -} - - - -/** - * Mark path as invalid: keep it aroud for a while to avoid trying it in a loop. - * - * DHT_get sometimes returns bad cached results, for instance, on a locally - * cached result where the PUT followed a path that is no longer current. - * - * @param p Path to invalidate. - */ -void -path_invalidate (struct CadetPeerPath *p) -{ - if (GNUNET_SCHEDULER_NO_TASK != p->path_delete) - return; - - p->path_delete = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, - &path_destroy_delayed, p); -} - - -/** - * Test if a path is valid (or at least not known to be invalid). - * - * @param path Path to test. - * - * @return #GNUNET_YES If the path is valid or unknown, - * #GNUNET_NO If the path is known to be invalid. - */ -int -path_is_valid (const struct CadetPeerPath *path) -{ - return (GNUNET_SCHEDULER_NO_TASK == path->path_delete); -} - - -/** - * Destroy the path and free any allocated resources linked to it - * - * @param p the path to destroy - * - * @return GNUNET_OK on success - */ -int -path_destroy (struct CadetPeerPath *p) -{ - if (NULL == p) - return GNUNET_OK; - - GNUNET_PEER_decrement_rcs (p->peers, p->length); - GNUNET_free_non_null (p->peers); - if (GNUNET_SCHEDULER_NO_TASK != p->path_delete) - GNUNET_SCHEDULER_cancel (p->path_delete); - GNUNET_free (p); - return GNUNET_OK; -} - -char * -path_2s (struct CadetPeerPath *p) -{ - char *s; - char *old; - unsigned int i; - - old = GNUNET_strdup (""); - for (i = 0; i < p->length; i++) - { - GNUNET_asprintf (&s, "%s %s", - old, GNUNET_i2s (GNUNET_PEER_resolve2 (p->peers[i]))); - GNUNET_free_non_null (old); - old = s; - } - return s; -} - -void -path_debug (struct CadetPeerPath *p) -{ - unsigned int i; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "PATH:\n"); - for (i = 0; i < p->length; i++) - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %s\n", - GNUNET_i2s (GNUNET_PEER_resolve2 (p->peers[i]))); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "END\n"); -} diff --git a/src/mesh/cadet_path.h b/src/mesh/cadet_path.h deleted file mode 100644 index 36bcfa5ae..000000000 --- a/src/mesh/cadet_path.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2001 - 2013 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 cadet/cadet_path.h - * @brief Path handling functions - * @author Bartlomiej Polot - */ - -#include "gnunet-service-cadet_connection.h" - -#ifndef CADET_PATH_H_ -#define CADET_PATH_H_ - -#ifdef __cplusplus -extern "C" -{ - #if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -/******************************************************************************/ -/************************ DATA STRUCTURES ****************************/ -/******************************************************************************/ - -/** - * Information regarding a possible path to reach a single peer - */ -struct CadetPeerPath -{ - - /** - * Linked list - */ - struct CadetPeerPath *next; - struct CadetPeerPath *prev; - - /** - * List of all the peers that form the path from origin to target. - */ - GNUNET_PEER_Id *peers; - - /** - * Number of peers (hops) in the path - */ - unsigned int length; - - /** - * User defined data store. - */ - struct CadetConnection *c; - - /** - * Path's score, how reliable is the path. - */ -// int score; - - /** - * Task to delete the path. - * We tried it, it didn't work, don't try again in a while. - */ - GNUNET_SCHEDULER_TaskIdentifier path_delete; - -}; - -/******************************************************************************/ -/************************* FUNCTIONS *****************************/ -/******************************************************************************/ - -/** - * Create a new path. - * - * @param length How many hops will the path have. - * - * @return A newly allocated path with a peer array of the specified length. - */ -struct CadetPeerPath * -path_new (unsigned int length); - - -/** - * Invert the path. - * - * @param path The path to invert. - */ -void -path_invert (struct CadetPeerPath *path); - - -/** - * Duplicate a path, incrementing short peer's rc. - * - * @param path The path to duplicate. - */ -struct CadetPeerPath * -path_duplicate (const struct CadetPeerPath *path); - - -/** - * Get the length of a path. - * - * @param path The path to measure, with the local peer at any point of it. - * - * @return Number of hops to reach destination. - * UINT_MAX in case the peer is not in the path. - */ -unsigned int -path_get_length (struct CadetPeerPath *path); - -/** - * Mark path as invalid: keep it aroud for a while to avoid trying it in a loop. - * - * DHT_get sometimes returns bad cached results, for instance, on a locally - * cached result where the PUT followed a path that is no longer current. - * - * @param p Path to invalidate. - */ -void -path_invalidate (struct CadetPeerPath *p); - -/** - * Test if a path is valid (or at least not known to be invalid). - * - * @param path Path to test. - * - * @return #GNUNET_YES If the path is valid or unknown, - * #GNUNET_NO If the path is known to be invalid. - */ -int -path_is_valid (const struct CadetPeerPath *path); - -/** - * Destroy the path and free any allocated resources linked to it - * - * @param p the path to destroy - * - * @return GNUNET_OK on success - */ -int -path_destroy (struct CadetPeerPath *p); - -/** - * Path -> allocated one line string. Caller must free. - * - * @param p Path. - */ -char * -path_2s (struct CadetPeerPath *p); - -/** - * Print info about the path for debug. - * - * @param p Path to debug. - */ -void -path_debug (struct CadetPeerPath *p); - -#if 0 /* keep Emacsens' auto-indent happy */ -{ - #endif - #ifdef __cplusplus -} -#endif - - -/* ifndef CADET_PATH_H */ -#endif diff --git a/src/mesh/cadet_protocol.h b/src/mesh/cadet_protocol.h deleted file mode 100644 index 19cdfe4a0..000000000 --- a/src/mesh/cadet_protocol.h +++ /dev/null @@ -1,459 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2001 - 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. -*/ - -/** - * @author Bartlomiej Polot - * @file cadet/cadet_protocol.h - */ - -#ifndef CADET_PROTOCOL_H_ -#define CADET_PROTOCOL_H_ - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "cadet.h" - -#ifdef __cplusplus - -struct GNUNET_CADET_TunnelMessage; -extern "C" -{ -#if 0 - /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -/******************************************************************************/ -/******************** CADET NETWORK MESSAGES **************************/ -/******************************************************************************/ - -GNUNET_NETWORK_STRUCT_BEGIN - -/** - * Message for cadet connection creation. - */ -struct GNUNET_CADET_ConnectionCreate -{ - /** - * Type: GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE - * - * Size: sizeof (struct GNUNET_CADET_ConnectionCreate) + - * path_length * sizeof (struct GNUNET_PeerIdentity) - */ - struct GNUNET_MessageHeader header; - - /** - * ID of the connection - */ - struct GNUNET_CADET_Hash cid; - - /** - * path_length structs defining the *whole* path from the origin [0] to the - * final destination [path_length-1]. - */ - /* struct GNUNET_PeerIdentity peers[path_length]; */ -}; - -/** - * Message for ack'ing a connection - */ -struct GNUNET_CADET_ConnectionACK -{ - /** - * Type: GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK - */ - struct GNUNET_MessageHeader header; - - /** - * ID of the connection. - */ - struct GNUNET_CADET_Hash cid; - -}; - - -/** - * Message for encapsulation of a Key eXchange message in a connection. - */ -struct GNUNET_CADET_KX -{ - /** - * Type: GNUNET_MESSAGE_TYPE_CADET_KX. - */ - struct GNUNET_MessageHeader header; - - /** - * ID of the connection. - */ - struct GNUNET_CADET_Hash cid; - - /* Specific KX message follows. */ -}; - - -/** - * Message transmitted with the signed ephemeral key of a peer. The - * session key is then derived from the two ephemeral keys (ECDHE). - * - * As far as possible, same as CORE's EphemeralKeyMessage. - */ -struct GNUNET_CADET_KX_Ephemeral -{ - - /** - * Message type is GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL. - */ - struct GNUNET_MessageHeader header; - - /** - * Status of the sender (should be in "enum PeerStateMachine"), nbo. - */ - int32_t sender_status GNUNET_PACKED; - - /** - * An ECC signature of the 'origin' asserting the validity of - * the given ephemeral key. - */ - struct GNUNET_CRYPTO_EddsaSignature signature; - - /** - * Information about what is being signed. - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - - /** - * At what time was this key created (beginning of validity). - */ - struct GNUNET_TIME_AbsoluteNBO creation_time; - - /** - * When does the given ephemeral key expire (end of validity). - */ - struct GNUNET_TIME_AbsoluteNBO expiration_time; - - /** - * Ephemeral public ECC key (always for NIST P-521) encoded in a format suitable - * for network transmission as created using 'gcry_sexp_sprint'. - */ - struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key; - - /** - * Public key of the signing peer (persistent version, not the ephemeral public key). - */ - struct GNUNET_PeerIdentity origin_identity; -}; - - -/** - * We're sending an (encrypted) PING to the other peer to check if he - * can decrypt. The other peer should respond with a PONG with the - * same content, except this time encrypted with the receiver's key. - */ -struct GNUNET_CADET_KX_Ping -{ - /** - * Message type is GNUNET_MESSAGE_TYPE_CADET_KX_PING. - */ - struct GNUNET_MessageHeader header; - - /** - * Seed for the IV - */ - uint32_t iv GNUNET_PACKED; - - /** - * Intended target of the PING, used primarily to check - * that decryption actually worked. - */ - struct GNUNET_PeerIdentity target; - - /** - * Random number chosen to make reply harder. - */ - uint32_t nonce GNUNET_PACKED; -}; - - -/** - * Response to a PING. Includes data from the original PING. - */ -struct GNUNET_CADET_KX_Pong -{ - /** - * Message type is GNUNET_MESSAGE_TYPE_CADET_KX_PONG. - */ - struct GNUNET_MessageHeader header; - - /** - * Seed for the IV - */ - uint32_t iv GNUNET_PACKED; - - /** - * Same nonce as in the reve. - */ - uint32_t nonce GNUNET_PACKED; -}; - - -/** - * Tunnel(ed) message. - */ -struct GNUNET_CADET_Encrypted -{ - /** - * Type: GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED - */ - struct GNUNET_MessageHeader header; - - /** - * ID of the connection. - */ - struct GNUNET_CADET_Hash cid; - - /** - * ID of the packet (hop by hop). - */ - uint32_t pid GNUNET_PACKED; - - /** - * Number of hops to live. - */ - uint32_t ttl GNUNET_PACKED; - - /** - * Initialization Vector for payload encryption. - */ - uint32_t iv GNUNET_PACKED; - - /** - * MAC of the encrypted message, used to verify message integrity. - * Everything after this value will be encrypted and authenticated. - */ - struct GNUNET_CADET_Hash hmac; - - /** - * Encrypted content follows. - */ -}; - - -/** - * Message to create a Channel. - */ -struct GNUNET_CADET_ChannelCreate -{ - /** - * Type: GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE - */ - struct GNUNET_MessageHeader header; - - /** - * ID of the channel - */ - CADET_ChannelNumber chid GNUNET_PACKED; - - /** - * Destination port. - */ - uint32_t port GNUNET_PACKED; - - /** - * Channel options. - */ - uint32_t opt GNUNET_PACKED; -}; - - -/** - * Message to manage a Channel (ACK, NACK, Destroy). - */ -struct GNUNET_CADET_ChannelManage -{ - /** - * Type: GNUNET_MESSAGE_TYPE_CADET_CHANNEL_{ACK|NACK|DESTROY} - */ - struct GNUNET_MessageHeader header; - - /** - * ID of the channel - */ - CADET_ChannelNumber chid GNUNET_PACKED; -}; - - -/** - * Message for cadet data traffic. - */ -struct GNUNET_CADET_Data -{ - /** - * Type: GNUNET_MESSAGE_TYPE_CADET_UNICAST, - * GNUNET_MESSAGE_TYPE_CADET_TO_ORIGIN - */ - struct GNUNET_MessageHeader header; - - /** - * Unique ID of the payload message - */ - uint32_t mid GNUNET_PACKED; - - /** - * ID of the channel - */ - CADET_ChannelNumber chid GNUNET_PACKED; - - /** - * Payload follows - */ -}; - - -/** - * Message to acknowledge end-to-end data. - */ -struct GNUNET_CADET_DataACK -{ - /** - * Type: GNUNET_MESSAGE_TYPE_CADET_DATA_ACK - */ - struct GNUNET_MessageHeader header; - - /** - * ID of the channel - */ - CADET_ChannelNumber chid GNUNET_PACKED; - - /** - * Bitfield of already-received newer messages - * pid + 1 @ LSB - * pid + 64 @ MSB - */ - uint64_t futures GNUNET_PACKED; - - /** - * Last message ID received. - */ - uint32_t mid GNUNET_PACKED; -}; - - -/** - * Message to acknowledge cadet encrypted traffic. - */ -struct GNUNET_CADET_ACK -{ - /** - * Type: GNUNET_MESSAGE_TYPE_CADET_ACK - */ - struct GNUNET_MessageHeader header; - - /** - * Maximum packet ID authorized. - */ - uint32_t ack GNUNET_PACKED; - - /** - * ID of the connection. - */ - struct GNUNET_CADET_Hash cid; -}; - - -/** - * Message to query a peer about its Flow Control status regarding a tunnel. - */ -struct GNUNET_CADET_Poll -{ - /** - * Type: GNUNET_MESSAGE_TYPE_CADET_POLL - */ - struct GNUNET_MessageHeader header; - - /** - * Last packet sent. - */ - uint32_t pid GNUNET_PACKED; - - /** - * ID of the connection. - */ - struct GNUNET_CADET_Hash cid; - -}; - - -/** - * Message for notifying a disconnection in a path - */ -struct GNUNET_CADET_ConnectionBroken -{ - /** - * Type: GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN - */ - struct GNUNET_MessageHeader header; - - /** - * ID of the connection. - */ - struct GNUNET_CADET_Hash cid; - - /** - * ID of the endpoint - */ - struct GNUNET_PeerIdentity peer1; - - /** - * ID of the endpoint - */ - struct GNUNET_PeerIdentity peer2; -}; - - -/** - * Message to destroy a connection. - */ -struct GNUNET_CADET_ConnectionDestroy -{ - /** - * Type: GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY - */ - struct GNUNET_MessageHeader header; - - /** - * ID of the connection. - */ - struct GNUNET_CADET_Hash cid; -}; - - -GNUNET_NETWORK_STRUCT_END - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef CADET_PROTOCOL_H */ -#endif -/* end of cadet_protocol.h */ diff --git a/src/mesh/cadet_test_lib.c b/src/mesh/cadet_test_lib.c deleted file mode 100644 index 663972cad..000000000 --- a/src/mesh/cadet_test_lib.c +++ /dev/null @@ -1,295 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2012 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 cadet/cadet_test_lib.c - * @author Bartlomiej Polot - * @brief library for writing CADET tests - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "cadet_test_lib.h" -#include "gnunet_cadet_service.h" - -/** - * Test context for a CADET Test. - */ -struct GNUNET_CADET_TEST_Context -{ - /** - * Array of running peers. - */ - struct GNUNET_TESTBED_Peer **peers; - - /** - * Array of handles to the CADET for each peer. - */ - struct GNUNET_CADET_Handle **cadetes; - - /** - * Operation associated with the connection to the CADET. - */ - struct GNUNET_TESTBED_Operation **ops; - - /** - * Main function of the test to run once all CADETs are available. - */ - GNUNET_CADET_TEST_AppMain app_main; - - /** - * Closure for 'app_main'. - */ - void *app_main_cls; - - /** - * Number of peers running, size of the arrays above. - */ - unsigned int num_peers; - - /** - * Handler for incoming tunnels. - */ - GNUNET_CADET_InboundChannelNotificationHandler *new_channel; - - /** - * Cleaner for destroyed incoming tunnels. - */ - GNUNET_CADET_ChannelEndHandler *cleaner; - - /** - * Message handlers. - */ - struct GNUNET_CADET_MessageHandler* handlers; - - /** - * Application ports. - */ - const uint32_t *ports; - -}; - - -/** - * Context for a cadet adapter callback. - */ -struct GNUNET_CADET_TEST_AdapterContext -{ - /** - * Peer number for the particular peer. - */ - unsigned int peer; - - /** - * General context. - */ - struct GNUNET_CADET_TEST_Context *ctx; -}; - - -/** - * Adapter function called to establish a connection to - * the CADET service. - * - * @param cls closure - * @param cfg configuration of the peer to connect to; will be available until - * GNUNET_TESTBED_operation_done() is called on the operation returned - * from GNUNET_TESTBED_service_connect() - * @return service handle to return in 'op_result', NULL on error - */ -static void * -cadet_connect_adapter (void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct GNUNET_CADET_TEST_AdapterContext *actx = cls; - struct GNUNET_CADET_TEST_Context *ctx = actx->ctx; - struct GNUNET_CADET_Handle *h; - - h = GNUNET_CADET_connect (cfg, - (void *) (long) actx->peer, - ctx->new_channel, - ctx->cleaner, - ctx->handlers, - ctx->ports); - return h; -} - - -/** - * Adapter function called to destroy a connection to - * the CADET service. - * - * @param cls closure - * @param op_result service handle returned from the connect adapter - */ -static void -cadet_disconnect_adapter (void *cls, - void *op_result) -{ - struct GNUNET_CADET_Handle *cadet = op_result; - struct GNUNET_CADET_TEST_AdapterContext *actx = cls; - - GNUNET_free (actx); - GNUNET_CADET_disconnect (cadet); -} - - -/** - * Callback to be called when a service connect operation is completed. - * - * @param cls The callback closure from functions generating an operation. - * @param op The operation that has been finished. - * @param ca_result The service handle returned from - * GNUNET_TESTBED_ConnectAdapter() (cadet handle). - * @param emsg Error message in case the operation has failed. - * NULL if operation has executed successfully. - */ -static void -cadet_connect_cb (void *cls, - struct GNUNET_TESTBED_Operation *op, - void *ca_result, - const char *emsg) -{ - struct GNUNET_CADET_TEST_Context *ctx = cls; - unsigned int i; - - if (NULL != emsg) - { - fprintf (stderr, "Failed to connect to CADET service: %s\n", - emsg); - GNUNET_SCHEDULER_shutdown (); - return; - } - for (i = 0; i < ctx->num_peers; i++) - if (op == ctx->ops[i]) - { - ctx->cadetes[i] = ca_result; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "...cadet %u connected\n", i); - } - for (i = 0; i < ctx->num_peers; i++) - if (NULL == ctx->cadetes[i]) - return; /* still some CADET connections missing */ - /* all CADET connections ready! */ - ctx->app_main (ctx->app_main_cls, - ctx, - ctx->num_peers, - ctx->peers, - ctx->cadetes); -} - - -void -GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx) -{ - unsigned int i; - - for (i = 0; i < ctx->num_peers; i++) - { - GNUNET_assert (NULL != ctx->ops[i]); - GNUNET_TESTBED_operation_done (ctx->ops[i]); - ctx->ops[i] = NULL; - } - GNUNET_free (ctx->ops); - GNUNET_free (ctx->cadetes); - GNUNET_free (ctx); - GNUNET_SCHEDULER_shutdown (); -} - - -/** - * Callback run when the testbed is ready (peers running and connected to - * each other) - * - * @param cls Closure (context). - * @param h the run handle - * @param num_peers Number of peers that are running. - * @param peers Handles to each one of the @c num_peers peers. - * @param links_succeeded the number of overlay link connection attempts that - * succeeded - * @param links_failed the number of overlay link connection attempts that - * failed - */ -static void -cadet_test_run (void *cls, - struct GNUNET_TESTBED_RunHandle *h, - unsigned int num_peers, - struct GNUNET_TESTBED_Peer **peers, - unsigned int links_succeeded, - unsigned int links_failed) -{ - struct GNUNET_CADET_TEST_Context *ctx = cls; - unsigned int i; - - if (num_peers != ctx->num_peers) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers started %u/%u, ending\n", - num_peers, ctx->num_peers); - exit (1); - } - ctx->peers = peers; - for (i = 0; i < num_peers; i++) - { - struct GNUNET_CADET_TEST_AdapterContext *newctx; - newctx = GNUNET_new (struct GNUNET_CADET_TEST_AdapterContext); - newctx->peer = i; - newctx->ctx = ctx; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting to cadet %u\n", i); - ctx->ops[i] = GNUNET_TESTBED_service_connect (ctx, - peers[i], - "cadet", - &cadet_connect_cb, - ctx, - &cadet_connect_adapter, - &cadet_disconnect_adapter, - newctx); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "op handle %p\n", ctx->ops[i]); - } -} - - -void -GNUNET_CADET_TEST_run (const char *testname, - const char *cfgname, - unsigned int num_peers, - GNUNET_CADET_TEST_AppMain tmain, - void *tmain_cls, - GNUNET_CADET_InboundChannelNotificationHandler new_channel, - GNUNET_CADET_ChannelEndHandler cleaner, - struct GNUNET_CADET_MessageHandler* handlers, - const uint32_t *ports) -{ - struct GNUNET_CADET_TEST_Context *ctx; - - ctx = GNUNET_new (struct GNUNET_CADET_TEST_Context); - ctx->num_peers = num_peers; - ctx->ops = GNUNET_malloc (num_peers * sizeof (struct GNUNET_TESTBED_Operation *)); - ctx->cadetes = GNUNET_malloc (num_peers * sizeof (struct GNUNET_CADET_Handle *)); - ctx->app_main = tmain; - ctx->app_main_cls = tmain_cls; - ctx->new_channel = new_channel; - ctx->cleaner = cleaner; - ctx->handlers = handlers; - ctx->ports = ports; - GNUNET_TESTBED_test_run (testname, - cfgname, - num_peers, - 0LL, NULL, NULL, - &cadet_test_run, ctx); -} - -/* end of cadet_test_lib.c */ diff --git a/src/mesh/cadet_test_lib.h b/src/mesh/cadet_test_lib.h deleted file mode 100644 index f2ed426b0..000000000 --- a/src/mesh/cadet_test_lib.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2012 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 cadet/cadet_test_lib.h - * @author Bartlomiej Polot - * @brief library for writing CADET tests - */ -#ifndef CADET_TEST_LIB_H -#define CADET_TEST_LIB_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "gnunet_testbed_service.h" -#include "gnunet_cadet_service.h" - -/** - * Test context for a CADET Test. - */ -struct GNUNET_CADET_TEST_Context; - - -/** - * Main function of a CADET test. - * - * @param cls Closure. - * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end. - * @param num_peers Number of peers that are running. - * @param peers Array of peers. - * @param cadetes Handle to each of the CADETs of the peers. - */ -typedef void (*GNUNET_CADET_TEST_AppMain) (void *cls, - struct GNUNET_CADET_TEST_Context *ctx, - unsigned int num_peers, - struct GNUNET_TESTBED_Peer **peers, - struct GNUNET_CADET_Handle **cadetes); - - -/** - * Run a test using the given name, configuration file and number of - * peers. - * All cadet callbacks will receive the peer number as the closure. - * - * @param testname Name of the test (for logging). - * @param cfgname Name of the configuration file. - * @param num_peers Number of peers to start. - * @param tmain Main function to run once the testbed is ready. - * @param tmain_cls Closure for 'tmain'. - * @param new_channel Handler for incoming tunnels. - * @param cleaner Cleaner for destroyed incoming tunnels. - * @param handlers Message handlers. - * @param ports Ports the peers offer. - */ -void -GNUNET_CADET_TEST_run (const char *testname, - const char *cfgname, - unsigned int num_peers, - GNUNET_CADET_TEST_AppMain tmain, - void *tmain_cls, - GNUNET_CADET_InboundChannelNotificationHandler new_channel, - GNUNET_CADET_ChannelEndHandler cleaner, - struct GNUNET_CADET_MessageHandler* handlers, - const uint32_t* ports); - - -/** - * Clean up the testbed. - * - * @param ctx handle for the testbed - */ -void -GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx); - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - - -/* ifndef CADET_TEST_LIB_H */ -#endif diff --git a/src/mesh/cadet_tunnel_tree.c b/src/mesh/cadet_tunnel_tree.c deleted file mode 100644 index dd3f3dae1..000000000 --- a/src/mesh/cadet_tunnel_tree.c +++ /dev/null @@ -1,1174 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2001 - 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 cadet/cadet_tunnel_tree.c - * @brief Tunnel tree handling functions - * @author Bartlomiej Polot - */ - -#include "cadet.h" -#include "cadet_tunnel_tree.h" - -#define CADET_TREE_DEBUG GNUNET_YES - - -/** - * Node of path tree for a tunnel - */ -struct CadetTunnelTreeNode -{ - /** - * Peer this node describes - */ - GNUNET_PEER_Id peer; - - /** - * Parent node in the tree - */ - struct CadetTunnelTreeNode *parent; - - /** - * DLL of siblings - */ - struct CadetTunnelTreeNode *next; - - /** - * DLL of siblings - */ - struct CadetTunnelTreeNode *prev; - - /** - * DLL of children - */ - struct CadetTunnelTreeNode *children_head; - - /** - * DLL of children - */ - struct CadetTunnelTreeNode *children_tail; - - /** - * Status of the peer in the tunnel - */ - enum CadetPeerState status; -}; - - -/** - * Tree to reach all peers in the tunnel - */ -struct CadetTunnelTree -{ - /** - * Root node of peer tree - */ - struct CadetTunnelTreeNode *root; - - /** - * Node that represents our position in the tree (for non local tunnels) - */ - struct CadetTunnelTreeNode *me; - - /** - * DLL of disconneted nodes - */ - struct CadetTunnelTreeNode *disconnected_head; - - /** - * DLL of disconneted nodes - */ - struct CadetTunnelTreeNode *disconnected_tail; - - /** - * Cache of all peers and the first hop to them. - * Indexed by PeerIdentity, contains a pointer to the PeerIdentity - * of 1st hop. - */ - struct GNUNET_CONTAINER_MultiHashMap *first_hops; - -}; - - -/** - * Create a new path - * - * @param length How many hops will the path have. - * - * @return A newly allocated path with a peer array of the specified length. - */ -struct CadetPeerPath * -path_new (unsigned int length) -{ - struct CadetPeerPath *p; - - p = GNUNET_new (struct CadetPeerPath); - if (length > 0) - { - p->length = length; - p->peers = GNUNET_malloc (length * sizeof (GNUNET_PEER_Id)); - } - return p; -} - - -/** - * Invert the path - * - * @param path the path to invert - */ -void -path_invert (struct CadetPeerPath *path) -{ - GNUNET_PEER_Id aux; - unsigned int i; - - for (i = 0; i < path->length / 2; i++) - { - aux = path->peers[i]; - path->peers[i] = path->peers[path->length - i - 1]; - path->peers[path->length - i - 1] = aux; - } -} - - -/** - * Duplicate a path, incrementing short peer's rc. - * - * @param path The path to duplicate. - */ -struct CadetPeerPath * -path_duplicate (struct CadetPeerPath *path) -{ - struct CadetPeerPath *aux; - unsigned int i; - - aux = path_new (path->length); - memcpy (aux->peers, path->peers, path->length * sizeof (GNUNET_PEER_Id)); - for (i = 0; i < path->length; i++) - GNUNET_PEER_change_rc (path->peers[i], 1); - return aux; -} - - -/** - * Recusively update the info about what is the first hop to reach the node - * - * @param tree Tree this nodes belongs to. - * @param parent The node form which to start updating. - * @param hop If known, ID of the first hop. - * If not known, NULL to find out and pass on children. - */ -static void -tree_node_update_first_hops (struct CadetTunnelTree *tree, - struct CadetTunnelTreeNode *parent, - struct GNUNET_PeerIdentity *hop); - - -/** - * Get the length of a path. - * - * @param path The path to measure, with the local peer at any point of it. - * - * @return Number of hops to reach destination. - * UINT_MAX in case the peer is not in the path. - */ -unsigned int -path_get_length (struct CadetPeerPath *path) -{ - if (NULL == path) - return UINT_MAX; - return path->length; -} - - -/** - * Destroy the path and free any allocated resources linked to it - * - * @param p the path to destroy - * - * @return GNUNET_OK on success - */ -int -path_destroy (struct CadetPeerPath *p) -{ - if (NULL == p) - return GNUNET_OK; - GNUNET_PEER_decrement_rcs (p->peers, p->length); - GNUNET_free_non_null (p->peers); - GNUNET_free (p); - return GNUNET_OK; -} - - - -/** - * Allocates and initializes a new node. - * Sets ID and parent of the new node and inserts it in the DLL of the parent - * - * @param parent Node that will be the parent from the new node, NULL for root - * @param peer Short Id of the new node - * - * @return Newly allocated node - */ -static struct CadetTunnelTreeNode * -tree_node_new (struct CadetTunnelTreeNode *parent, GNUNET_PEER_Id peer) -{ - struct CadetTunnelTreeNode *node; - - node = GNUNET_new (struct CadetTunnelTreeNode); - node->peer = peer; - GNUNET_PEER_change_rc (peer, 1); - node->parent = parent; - if (NULL != parent) - GNUNET_CONTAINER_DLL_insert (parent->children_head, parent->children_tail, - node); - - return node; -} - - -/** - * Recursively find the given peer. - * - * @param parent Node where to start looking. - * @param peer_id Short ID of the peer to find. - * - * @return Pointer to the node of the peer. NULL if not found. - */ -static struct CadetTunnelTreeNode * -tree_node_find_peer (struct CadetTunnelTreeNode *parent, GNUNET_PEER_Id peer_id) -{ - struct CadetTunnelTreeNode *n; - struct CadetTunnelTreeNode *r; - - if (parent->peer == peer_id) - return parent; - for (n = parent->children_head; NULL != n; n = n->next) - { - r = tree_node_find_peer (n, peer_id); - if (NULL != r) - return r; - } - return NULL; -} - - -/** - * Recusively update the info about what is the first hop to reach the node - * - * @param tree Tree this nodes belongs to. - * @param parent ID from node form which to start updating. - * @param hop If known, ID of the first hop. - * If not known, NULL to find out and pass on children. - */ -static void -tree_node_update_first_hops (struct CadetTunnelTree *tree, - struct CadetTunnelTreeNode *parent, - struct GNUNET_PeerIdentity *hop) -{ - struct GNUNET_PeerIdentity pi; - struct GNUNET_PeerIdentity *copy; - struct GNUNET_PeerIdentity id; - struct CadetTunnelTreeNode *n; - -#if CADET_TREE_DEBUG - GNUNET_PEER_resolve (parent->peer, &id); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Finding first hop for %s.\n", - GNUNET_i2s (&id)); -#endif - if (NULL == hop) - { - struct CadetTunnelTreeNode *aux; - struct CadetTunnelTreeNode *old; - - aux = old = parent; - while (aux != tree->me) - { -#if CADET_TREE_DEBUG - GNUNET_PEER_resolve (aux->peer, &id); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: ... checking %s.\n", - GNUNET_i2s (&id)); -#endif - old = aux; - aux = aux->parent; - GNUNET_assert (NULL != aux); - } -#if CADET_TREE_DEBUG - GNUNET_PEER_resolve (old->peer, &id); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: It's %s!\n", - GNUNET_i2s (&id)); -#endif - hop = π - GNUNET_PEER_resolve (old->peer, hop); - } - GNUNET_PEER_resolve (parent->peer, &id); - copy = GNUNET_CONTAINER_multihashmap_get (tree->first_hops, &id.hashPubKey); - if (NULL == copy) - copy = GNUNET_new (struct GNUNET_PeerIdentity); - *copy = *hop; - - (void) GNUNET_CONTAINER_multihashmap_put (tree->first_hops, &id.hashPubKey, - copy, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); - - for (n = parent->children_head; NULL != n; n = n->next) - { - tree_node_update_first_hops (tree, n, hop); - } -} - - -static void -tree_node_debug (struct CadetTunnelTreeNode *n, uint16_t level) -{ - struct CadetTunnelTreeNode *c; - struct GNUNET_PeerIdentity id;; - uint16_t i; - - for (i = 0; i < level; i++) - FPRINTF (stderr, "%s", " "); - if (n->status == CADET_PEER_READY) - FPRINTF (stderr, "%s", "#"); - if (n->status == CADET_PEER_SEARCHING) - FPRINTF (stderr, "%s", "+"); - if (n->status == CADET_PEER_RELAY) - FPRINTF (stderr, "%s", "-"); - if (n->status == CADET_PEER_RECONNECTING) - FPRINTF (stderr, "%s", "*"); - - GNUNET_PEER_resolve (n->peer, &id); - FPRINTF (stderr, "%s, [%u, %p] ", GNUNET_i2s (&id), n->peer, n); - if (NULL != n->parent) - { - GNUNET_PEER_resolve (n->parent->peer, &id); - FPRINTF (stderr, "(-> %s [%u])\n", GNUNET_i2s (&id), n->parent->peer); - } - else - FPRINTF (stderr, "%s", "(root)\n"); - for (c = n->children_head; NULL != c; c = c->next) - tree_node_debug (c, level + 1); -} - - -/** - * Destroys and frees the node and all children - * - * @param parent Parent node to be destroyed - */ -static void -tree_node_destroy (struct CadetTunnelTreeNode *parent) -{ - struct CadetTunnelTreeNode *n; - struct CadetTunnelTreeNode *next; - - if (NULL == parent) - return; -#if CADET_TREE_DEBUG - struct GNUNET_PeerIdentity id; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Destroying node %u\n", - parent->peer); - GNUNET_PEER_resolve (parent->peer, &id); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: (%s)\n", GNUNET_i2s (&id)); -#endif - n = parent->children_head; - while (NULL != n) - { - next = n->next; - tree_node_destroy (n); - n = next; - } - GNUNET_PEER_change_rc (parent->peer, -1); - if (NULL != parent->parent) - GNUNET_CONTAINER_DLL_remove (parent->parent->children_head, - parent->parent->children_tail, parent); - GNUNET_free (parent); -} - - - -/** - * Create a new tree. - * - * @param peer A short peer id of the root of the tree. - * - * @return A newly allocated and initialized tunnel tree. - */ -struct CadetTunnelTree * -tree_new (GNUNET_PEER_Id peer) -{ - struct CadetTunnelTree *tree; - - tree = GNUNET_new (struct CadetTunnelTree); - tree->first_hops = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO); - tree->root = tree_node_new (NULL, peer); - tree->root->status = CADET_PEER_ROOT; - - if (1 == peer) - { - tree->me = tree->root; - } - - return tree; -} - - -/** - * Set the status of a node. - * - * @param tree Tree. - * @param peer A short peer id of the node. - * @param status New status to set. - */ -void -tree_set_status (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer, - enum CadetPeerState status) -{ - struct CadetTunnelTreeNode *n; - - n = tree_find_peer (tree, peer); - if (NULL == n) - return; - n->status = status; -} - - -/** - * Get the status of a node. - * - * @param tree Tree whose node's status we want to now. - * @param peer A short peer id of the node. - * - * @return Status of the peer. - */ -enum CadetPeerState -tree_get_status (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer) -{ - struct CadetTunnelTreeNode *n; - - n = tree_find_peer (tree, peer); - if (NULL == n) - return CADET_PEER_INVALID; - return n->status; -} - - -/** - * Get the id of the predecessor of the local node. - * - * @param tree Tree whose local id we want to now. - * - * @return Short peer id of local peer. - */ -GNUNET_PEER_Id -tree_get_predecessor (struct CadetTunnelTree *tree) -{ - if (NULL != tree->me && NULL != tree->me->parent) - return tree->me->parent->peer; - else - return (GNUNET_PEER_Id) 0; -} - - -/** - * Find the first peer whom to send a packet to go down this path - * - * @param t The tunnel tree to use - * @param peer The peerinfo of the peer we are trying to reach - * - * @return peerinfo of the peer who is the first hop in the tunnel - * NULL on error - * - * FIXME use PEER_Id - */ -struct GNUNET_PeerIdentity * -tree_get_first_hop (struct CadetTunnelTree *t, GNUNET_PEER_Id peer) -{ - struct GNUNET_PeerIdentity id; - struct GNUNET_PeerIdentity *r; - - GNUNET_PEER_resolve (peer, &id); - r = GNUNET_CONTAINER_multihashmap_get (t->first_hops, &id.hashPubKey); - if (NULL == r) - { - struct CadetTunnelTreeNode *n; - - n = tree_find_peer (t, peer); - if (NULL != t->me && NULL != n) - { - tree_node_update_first_hops (t, n, NULL); - r = GNUNET_CONTAINER_multihashmap_get (t->first_hops, &id.hashPubKey); - GNUNET_assert (NULL != r); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Tree structure inconsistent! me: %p, n: %p", t->me, n); - GNUNET_break (0); - } - } - - return r; -} - - -/** - * Find the given peer in the tree. - * - * @param tree Tree where to look for the peer. - * @param peer_id Short ID of the peer to find. - * - * @return Pointer to the node of the peer. NULL if not found. - */ -struct CadetTunnelTreeNode * -tree_find_peer (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer_id) -{ - return tree_node_find_peer (tree->root, peer_id); -} - - -/** - * Recusively mark peer and children as disconnected, notify client - * - * @param tree Tree this node belongs to - * @param parent Node to be clean, potentially with children - * @param cb Callback to use to notify about disconnected peers. - * @param cbcls Closure for cb. - */ -static void -tree_mark_peers_disconnected (struct CadetTunnelTree *tree, - struct CadetTunnelTreeNode *parent, - CadetTreeCallback cb, void *cbcls) -{ - struct GNUNET_PeerIdentity *pi; - struct GNUNET_PeerIdentity id; - struct CadetTunnelTreeNode *n; - - for (n = parent->children_head; NULL != n; n = n->next) - { - tree_mark_peers_disconnected (tree, n, cb, cbcls); - } - if (CADET_PEER_READY == parent->status) - { - if (NULL != cb) - cb (cbcls, parent->peer); - parent->status = CADET_PEER_RECONNECTING; - } - - /* Remove and free info about first hop */ - GNUNET_PEER_resolve (parent->peer, &id); - pi = GNUNET_CONTAINER_multihashmap_get (tree->first_hops, &id.hashPubKey); - GNUNET_CONTAINER_multihashmap_remove_all (tree->first_hops, &id.hashPubKey); - if (NULL != pi) - GNUNET_free (pi); -} - - -/** - * Iterate over all children of the local node. - * - * @param tree Tree to use. Must have "me" set. - * @param cb Callback to call over each child. - * @param cb_cls Closure for @c cb. - */ -void -tree_iterate_children (struct CadetTunnelTree *tree, CadetTreeCallback cb, - void *cb_cls) -{ - struct CadetTunnelTreeNode *n; - - if (NULL == tree->me) - return; - for (n = tree->me->children_head; NULL != n; n = n->next) - { - cb (cb_cls, n->peer); - } -} - - -/** - * Struct to contain a list of pending nodes when iterating a tree. - */ -struct CadetTreePendingNode { - - /** - * DLL next. - */ - struct CadetTreePendingNode *next; - - /** - * DLL prev. - */ - struct CadetTreePendingNode *prev; - - /** - * Pending node. - */ - struct CadetTunnelTreeNode *node; -}; - - -/** - * Iterate over all nodes in the tree. - * - * @param tree Tree to use.. - * @param cb Callback to call over each child. - * @param cb_cls Closure for @c cb. - * - * TODO: recursive implementation? (s/heap/stack/g) - */ -void -tree_iterate_all (struct CadetTunnelTree *tree, - CadetWholeTreeCallback cb, - void *cb_cls) -{ - struct CadetTunnelTreeNode *parent; - struct CadetTunnelTreeNode *n; - struct CadetTreePendingNode *head; - struct CadetTreePendingNode *tail; - struct CadetTreePendingNode *pending; - - cb (cb_cls, tree->root->peer, 0); - pending = GNUNET_new (struct CadetTreePendingNode); - pending->node = tree->root; - head = tail = NULL; - GNUNET_CONTAINER_DLL_insert (head, tail, pending); - - while (NULL != head) - { - pending = head; - parent = pending->node; - GNUNET_CONTAINER_DLL_remove (head, tail, pending); - GNUNET_free (pending); - for (n = parent->children_head; NULL != n; n = n->next) - { - cb (cb_cls, n->peer, parent->peer); - pending = GNUNET_new (struct CadetTreePendingNode); - pending->node = n; - /* Insert_tail: breadth first, Insert: depth first */ - GNUNET_CONTAINER_DLL_insert (head, tail, pending); - } - } -} - - -/** - * Iterator to count the children in a tree. - */ -static void -count_children_cb (void *cls, GNUNET_PEER_Id peer) -{ - unsigned int *i = cls; - - (*i)++; -} - - -/** - * Count how many children does the local node have in the tree. - * - * @param tree Tree to use. Must have "me" set. - */ -unsigned int -tree_count_children (struct CadetTunnelTree *tree) -{ - unsigned int i; - - i = 0; - tree_iterate_children(tree, &count_children_cb, &i); - return i; -} - - -/** - * Recusively update the info about what is the first hop to reach the node - * - * @param tree Tree this nodes belongs to. - * @param parent_id Short ID from node form which to start updating. - * @param hop If known, ID of the first hop. - * If not known, NULL to find out and pass on children. - */ -void -tree_update_first_hops (struct CadetTunnelTree *tree, GNUNET_PEER_Id parent_id, - struct GNUNET_PeerIdentity *hop) -{ - tree_node_update_first_hops (tree, tree_find_peer (tree, parent_id), hop); -} - - -/** - * Delete the current path to the peer, including all now unused relays. - * The destination peer is NOT destroyed, it is returned in order to either set - * a new path to it or destroy it explicitly, taking care of it's child nodes. - * - * @param t Tunnel tree where to delete the path from. - * @param peer_id Short ID of the destination peer whose path we want to remove. - * @param cb Callback to use to notify about disconnected peers. - * @param cbcls Closure for cb. - * - * @return pointer to the pathless node. - * NULL when not found - */ -struct CadetTunnelTreeNode * -tree_del_path (struct CadetTunnelTree *t, GNUNET_PEER_Id peer_id, - CadetTreeCallback cb, void *cbcls) -{ - struct CadetTunnelTreeNode *parent; - struct CadetTunnelTreeNode *node; - struct CadetTunnelTreeNode *n; - -#if CADET_TREE_DEBUG - struct GNUNET_PeerIdentity id; - - GNUNET_PEER_resolve (peer_id, &id); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Deleting path to %s.\n", - GNUNET_i2s (&id)); -#endif - if (NULL == t->root || peer_id == t->root->peer) - return NULL; - - for (n = t->disconnected_head; NULL != n; n = n->next) - { - if (n->peer == peer_id) - { - /* Was already pathless, waiting for reconnection */ - GNUNET_CONTAINER_DLL_remove (t->disconnected_head, t->disconnected_tail, - n); - return n; - } - } - n = tree_find_peer (t, peer_id); - if (NULL == n) - return NULL; - node = n; - - parent = n->parent; - GNUNET_CONTAINER_DLL_remove (parent->children_head, parent->children_tail, n); - n->parent = NULL; - - while (CADET_PEER_RELAY == parent->status && - NULL == parent->children_head) - { -#if CADET_TREE_DEBUG - GNUNET_PEER_resolve (parent->peer, &id); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Deleting node %s.\n", - GNUNET_i2s (&id)); -#endif - n = parent->parent; - if (parent == t->me) - t->me = NULL; - tree_node_destroy (parent); - parent = n; - } -#if CADET_TREE_DEBUG - GNUNET_PEER_resolve (parent->peer, &id); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Not deleted peer %s.\n", - GNUNET_i2s (&id)); -#endif - - tree_mark_peers_disconnected (t, node, cb, cbcls); - - return node; -} - - -/** - * Return a newly allocated individual path to reach a peer from the local peer, - * according to the path tree of some tunnel. - * - * @param t Tunnel from which to read the path tree. - * @param peer Short ID of the destination peer to whom we want a path. - * - * @return A newly allocated individual path to reach the destination peer. - * Path must be destroyed afterwards. - */ -struct CadetPeerPath * -tree_get_path_to_peer (struct CadetTunnelTree *t, GNUNET_PEER_Id peer) -{ - struct CadetTunnelTreeNode *n; - struct CadetPeerPath *p; - - n = tree_find_peer (t, peer); - if (NULL == n) - { - GNUNET_break (0); - return NULL; - } - p = path_new (0); - - /* Building the path (inverted!) */ - while (n->peer != 1) - { - GNUNET_array_append (p->peers, p->length, n->peer); - GNUNET_PEER_change_rc (n->peer, 1); - n = n->parent; - if (NULL == n) - { - GNUNET_break (0); - path_destroy (p); - return NULL; - } - } - GNUNET_array_append (p->peers, p->length, 1); - GNUNET_PEER_change_rc (1, 1); - - path_invert (p); - - return p; -} - - - -/** - * Integrate a stand alone path into the tunnel tree. - * If the peer toward which the new path is already in the tree, the peer - * and its children will be maked as disconnected and the callback - * will be called on each one of them. They will be maked as online only after - * receiving a PATH ACK for the new path for each one of them, so the caller - * should take care of sending a new CREATE PATH message for each disconnected - * peer. - * - * @param t Tunnel where to add the new path. - * @param p Path to be integrated. - * @param cb Callback to use to notify about peers temporarily disconnecting. - * @param cbcls Closure for cb. - * - * @return GNUNET_OK in case of success. - * GNUNET_SYSERR in case of error. - * - * TODO: optimize - * - go backwards on path looking for each peer in the present tree - * - do not disconnect peers until new path is created & connected - */ -int -tree_add_path (struct CadetTunnelTree *t, const struct CadetPeerPath *p, - CadetTreeCallback cb, void *cbcls) -{ - struct CadetTunnelTreeNode *parent; - struct CadetTunnelTreeNode *oldnode; - struct CadetTunnelTreeNode *n; - struct CadetTunnelTreeNode *c; - struct GNUNET_PeerIdentity id; - int me; - unsigned int i; - -#if CADET_TREE_DEBUG - GNUNET_PEER_resolve (p->peers[p->length - 1], &id); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "tree: Adding path [%u] towards peer %s.\n", p->length, - GNUNET_i2s (&id)); -#endif - - GNUNET_assert (0 != p->length); - parent = n = t->root; - if (n->peer != p->peers[0]) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (1 == p->length) - return GNUNET_OK; - oldnode = tree_del_path (t, p->peers[p->length - 1], cb, cbcls); - /* Look for the first node that is not already present in the tree - * - * Assuming that the tree is somewhat balanced, O(log n * log N). - * - Length of the path is expected to be log N (size of whole network). - * - Each level of the tree is expected to have log n children (size of tree). - */ - me = t->root->peer == 1 ? 0 : -1; - for (i = 1; i < p->length; i++) - { -#if CADET_TREE_DEBUG - GNUNET_PEER_resolve (p->peers[i], &id); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Looking for peer %s.\n", - GNUNET_i2s (&id)); -#endif - parent = n; - if (p->peers[i] == 1) - me = i; - for (c = n->children_head; NULL != c; c = c->next) - { - if (c->peer == p->peers[i]) - { -#if CADET_TREE_DEBUG - GNUNET_PEER_resolve (parent->peer, &id); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "tree: Found in children of %s.\n", GNUNET_i2s (&id)); -#endif - n = c; - break; - } - } - /* If we couldn't find a child equal to path[i], we have reached the end - * of the common path. */ - if (parent == n) - break; - } -#if CADET_TREE_DEBUG - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: All childen visited.\n"); -#endif - /* Add the rest of the path as a branch from parent. */ - while (i < p->length) - { -#if CADET_TREE_DEBUG - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Adding peer %u to %u.\n", - p->peers[i], parent->peer); - GNUNET_PEER_resolve (p->peers[i], &id); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Adding peer %s.\n", - GNUNET_i2s (&id)); - GNUNET_PEER_resolve (parent->peer, &id); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: to %s.\n", - GNUNET_i2s (&id)); -#endif - - if (i == p->length - 1 && NULL != oldnode) - { -#if CADET_TREE_DEBUG - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "tree: Putting old node into place.\n"); -#endif - oldnode->parent = parent; - GNUNET_CONTAINER_DLL_insert (parent->children_head, parent->children_tail, - oldnode); - tree_node_update_first_hops (t, oldnode, NULL); - n = oldnode; - } - else - { -#if CADET_TREE_DEBUG - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Creating new node.\n"); -#endif - n = tree_node_new (parent, p->peers[i]); - n->status = CADET_PEER_RELAY; - } - if (n->peer == 1) - { - t->me = n; - me = i; - } - i++; - parent = n; - } - n->status = CADET_PEER_SEARCHING; - - GNUNET_break (-1 != me); - - /* Add info about first hop into hashmap. */ - if (-1 != me && me < p->length - 1) - { -#if CADET_TREE_DEBUG - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "CADET: finding first hop (own pos %d/%u)\n", me, - p->length - 1); -#endif - GNUNET_PEER_resolve (p->peers[me + 1], &id); - tree_update_first_hops (t, p->peers[me + 1], &id); - } -#if CADET_TREE_DEBUG - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "CADET: was last in path, not updating first hops (%d/%u)\n", - me, p->length - 1); - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: New node added.\n"); -#endif - if (NULL == t->me) - t->me = tree_find_peer (t, 1); - return GNUNET_OK; -} - - -/** - * Notifies a tree that a connection it might be using is broken. - * Marks all peers down the paths as disconnected and notifies the client. - * - * @param t Tree to use. - * @param p1 Short id of one of the peers (order unimportant) - * @param p2 Short id of one of the peers (order unimportant) - * @param cb Function to call for every peer that is marked as disconnected. - * @param cbcls Closure for cb. - * - * @return Short ID of the first disconnected peer in the tree. - */ -GNUNET_PEER_Id -tree_notify_connection_broken (struct CadetTunnelTree *t, GNUNET_PEER_Id p1, - GNUNET_PEER_Id p2, CadetTreeCallback cb, - void *cbcls) -{ - struct CadetTunnelTreeNode *n; - struct CadetTunnelTreeNode *c; - - n = tree_find_peer (t, p1); - if (NULL == n) - return 0; - if (NULL != n->parent && n->parent->peer == p2) - { - tree_mark_peers_disconnected (t, n, cb, cbcls); - GNUNET_CONTAINER_DLL_remove (n->parent->children_head, - n->parent->children_tail, n); - GNUNET_CONTAINER_DLL_insert (t->disconnected_head, t->disconnected_tail, n); - return p1; - } - for (c = n->children_head; NULL != c; c = c->next) - { - if (c->peer == p2) - { - tree_mark_peers_disconnected (t, c, cb, cbcls); - GNUNET_CONTAINER_DLL_remove (n->children_head, n->children_tail, c); - GNUNET_CONTAINER_DLL_insert (t->disconnected_head, t->disconnected_tail, - c); - return p2; - } - } - return 0; -} - - -/** - * Deletes a peer from a tunnel, liberating all unused resources on the path to - * it. It shouldn't have children, if it has they will be destroyed as well. - * If the tree is not local and no longer has any paths, the root node will be - * destroyed and marked as NULL. - * - * @param t Tunnel tree to use. - * @param peer Short ID of the peer to remove from the tunnel tree. - * @param cb Callback to notify client of disconnected peers. - * @param cbcls Closure for cb. - * - * @return GNUNET_OK or GNUNET_SYSERR - */ -int -tree_del_peer (struct CadetTunnelTree *t, GNUNET_PEER_Id peer, - CadetTreeCallback cb, void *cbcls) -{ - struct CadetTunnelTreeNode *n; - - n = tree_del_path (t, peer, cb, cbcls); - if (NULL == n) - { - GNUNET_break (0); - return GNUNET_YES; - } - tree_node_destroy (n); - if (NULL == t->root->children_head && t->me != t->root) - { - tree_node_destroy (t->root); - t->root = NULL; - return GNUNET_NO; - } - return GNUNET_YES; -} - - - -/** - * Get the cost of the path relative to the already built tunnel tree. - * - * @param t The tunnel tree to which compare. - * @param path The individual path to reach a peer. It has to start at the - * root of the tree to be comparable. - * - * @return Number of hops to reach destination, UINT_MAX in case the peer is not - * in the path. - * - * TODO: adapt to allow any start / root combination - * TODO: take in account state of the nodes - */ -unsigned int -tree_get_path_cost (struct CadetTunnelTree *t, struct CadetPeerPath *path) -{ - struct CadetTunnelTreeNode *n; - struct CadetTunnelTreeNode *p; - unsigned int i; - unsigned int l; - - l = path_get_length (path); - p = t->root; - if (t->root->peer != path->peers[0]) - { - GNUNET_break (0); - return UINT_MAX; - } - for (i = 1; i < l; i++) - { - for (n = p->children_head; NULL != n; n = n->next) - { - if (path->peers[i] == n->peer) - { - break; - } - } - if (NULL == n) - return l - i; - p = n; - } - return l - i; -} - - -/** - * Print the tree on stderr - * - * @param t The tree - */ -void -tree_debug (struct CadetTunnelTree *t) -{ - tree_node_debug (t->root, 0); - FPRINTF (stderr, "root: %p\n", t->root); - FPRINTF (stderr, "me: %p\n", t->me); -} - - -/** - * Iterator over hash map peer entries and frees all data in it. - * Used prior to destroying a hashmap. Makes you miss anonymous functions in C. - * - * @param cls closure - * @param key current key code (will no longer contain valid data!!) - * @param value value in the hash map (treated as void *) - * @return GNUNET_YES if we should continue to iterate, GNUNET_NO if not. - */ -static int -iterate_free (void *cls, const struct GNUNET_HashCode * key, void *value) -{ - GNUNET_free (value); - return GNUNET_YES; -} - - -/** - * Destroy the whole tree and free all used memory and Peer_Ids - * - * @param t Tree to be destroyed - */ -void -tree_destroy (struct CadetTunnelTree *t) -{ -#if CADET_TREE_DEBUG - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Destroying tree\n"); -#endif - tree_node_destroy (t->root); - GNUNET_CONTAINER_multihashmap_iterate (t->first_hops, &iterate_free, NULL); - GNUNET_CONTAINER_multihashmap_destroy (t->first_hops); - GNUNET_free (t); -} diff --git a/src/mesh/cadet_tunnel_tree.h b/src/mesh/cadet_tunnel_tree.h deleted file mode 100644 index 779d330e7..000000000 --- a/src/mesh/cadet_tunnel_tree.h +++ /dev/null @@ -1,382 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2001 - 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 cadet/cadet_tunnel_tree.h - * @brief Tunnel tree handling functions - * @author Bartlomiej Polot - */ - -#include "cadet.h" - -/******************************************************************************/ -/************************ DATA STRUCTURES ****************************/ -/******************************************************************************/ - -/** - * Information regarding a possible path to reach a single peer - */ -struct CadetPeerPath -{ - - /** - * Linked list - */ - struct CadetPeerPath *next; - struct CadetPeerPath *prev; - - /** - * List of all the peers that form the path from origin to target. - */ - GNUNET_PEER_Id *peers; - - /** - * Number of peers (hops) in the path - */ - unsigned int length; - -}; - - -/** - * Node of path tree for a tunnel - */ -struct CadetTunnelTreeNode; - - -/** - * Tree to reach all peers in the tunnel - */ -struct CadetTunnelTree; - - -/******************************************************************************/ -/************************* FUNCTIONS *****************************/ -/******************************************************************************/ - -/** - * Create a new path. - * - * @param length How many hops will the path have. - * - * @return A newly allocated path with a peer array of the specified length. - */ -struct CadetPeerPath * -path_new (unsigned int length); - - -/** - * Invert the path. - * - * @param path The path to invert. - */ -void -path_invert (struct CadetPeerPath *path); - - -/** - * Duplicate a path, incrementing short peer's rc. - * - * @param path The path to duplicate. - */ -struct CadetPeerPath * -path_duplicate (struct CadetPeerPath *path); - - -/** - * Get the length of a path. - * - * @param path The path to measure, with the local peer at any point of it. - * - * @return Number of hops to reach destination. - * UINT_MAX in case the peer is not in the path. - */ -unsigned int -path_get_length (struct CadetPeerPath *path); - - -/** - * Destroy the path and free any allocated resources linked to it - * - * @param p the path to destroy - * - * @return GNUNET_OK on success - */ -int -path_destroy (struct CadetPeerPath *p); - - -/******************************************************************************/ - -/** - * Iterator over all children of a node. - * - * @param cls Closure. - * @param peer_id Short ID of the peer. - */ -typedef void (*CadetTreeCallback) (void *cls, GNUNET_PEER_Id peer_id); - - -/** - * Iterator over all nodes in a tree. - * - * @param cls Closure. - * @param peer_id Short ID of the peer. - * @param peer_id Short ID of the parent of the peer. - */ -typedef void (*CadetWholeTreeCallback) (void *cls, - GNUNET_PEER_Id peer_id, - GNUNET_PEER_Id parent_id); - -/** - * Create a new tunnel tree associated to a tunnel - * - * @param peer A short peer id of the root of the tree - * - * @return A newly allocated and initialized tunnel tree - */ -struct CadetTunnelTree * -tree_new (GNUNET_PEER_Id peer); - - -/** - * Set the status of a node. - * - * @param tree Tree. - * @param peer A short peer id of the node. - * @param status New status to set. - */ -void -tree_set_status (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer, - enum CadetPeerState status); - - -/** - * Get the status of a node. - * - * @param tree Tree whose local id we want to now. - * @param peer A short peer id of the node. - * - * @return Short peer id of local peer. - */ -enum CadetPeerState -tree_get_status (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer); - - -/** - * Get the id of the predecessor of the local node. - * - * @param tree Tree whose local id we want to now. - * - * @return Short peer id of local peer. - */ -GNUNET_PEER_Id -tree_get_predecessor (struct CadetTunnelTree *tree); - - -/** - * Find the first peer whom to send a packet to go down this path - * - * @param t The tunnel tree to use - * @param peer The peerinfo of the peer we are trying to reach - * - * @return peerinfo of the peer who is the first hop in the tunnel - * NULL on error - */ -struct GNUNET_PeerIdentity * -tree_get_first_hop (struct CadetTunnelTree *t, GNUNET_PEER_Id peer); - - -/** - * Find the given peer in the tree. - * - * @param tree Tree where to look for the peer. - * @param peer_id Peer to find. - * - * @return Pointer to the node of the peer. NULL if not found. - */ -struct CadetTunnelTreeNode * -tree_find_peer (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer_id); - - -/** - * Iterate over all children of the local node. - * - * @param tree Tree to use. Must have "me" set. - * @param cb Callback to call over each child. - * @param cb_cls Closure for @c cb. - */ -void -tree_iterate_children (struct CadetTunnelTree *tree, - CadetTreeCallback cb, - void *cb_cls); - - -/** - * Iterate over all nodes in the tree. - * - * @param tree Tree to use.. - * @param cb Callback to call over each child. - * @param cb_cls Closure for @c cb. - * - * TODO: recursive implementation? (s/heap/stack/g) - */ -void -tree_iterate_all (struct CadetTunnelTree *tree, - CadetWholeTreeCallback cb, - void *cb_cls); - -/** - * Count how many children does the local node have in the tree. - * - * @param tree Tree to use. Must have "me" set. - */ -unsigned int -tree_count_children (struct CadetTunnelTree *tree); - - -/** - * Recusively update the info about what is the first hop to reach the node - * - * @param tree Tree this nodes belongs to. - * @param parent_id Short ID from node form which to start updating. - * @param hop If known, ID of the first hop. - * If not known, NULL to find out and pass on children. - */ -void -tree_update_first_hops (struct CadetTunnelTree *tree, GNUNET_PEER_Id parent_id, - struct GNUNET_PeerIdentity *hop); - -/** - * Delete the current path to the peer, including all now unused relays. - * The destination peer is NOT destroyed, it is returned in order to either set - * a new path to it or destroy it explicitly, taking care of it's child nodes. - * - * @param t Tunnel tree where to delete the path from. - * @param peer_id Short ID of the destination peer whose path we want to remove. - * @param cb Callback to use to notify about which peers are going to be - * disconnected. - * @param cbcls Closure for cb. - * - * @return pointer to the pathless node. - * NULL when not found - */ -struct CadetTunnelTreeNode * -tree_del_path (struct CadetTunnelTree *t, GNUNET_PEER_Id peer_id, - CadetTreeCallback cb, void *cbcls); - - -/** - * Return a newly allocated individual path to reach a peer from the local peer, - * according to the path tree of some tunnel. - * - * @param t Tunnel from which to read the path tree - * @param peer Destination peer to whom we want a path - * - * @return A newly allocated individual path to reach the destination peer. - * Path must be destroyed afterwards. - */ -struct CadetPeerPath * -tree_get_path_to_peer (struct CadetTunnelTree *t, GNUNET_PEER_Id peer); - - -/** - * Integrate a stand alone path into the tunnel tree. - * - * @param t Tunnel where to add the new path. - * @param p Path to be integrated. - * @param cb Callback to use to notify about peers temporarily disconnecting. - * @param cbcls Closure for cb. - * - * @return GNUNET_OK in case of success. - * GNUNET_SYSERR in case of error. - */ -int -tree_add_path (struct CadetTunnelTree *t, const struct CadetPeerPath *p, - CadetTreeCallback cb, void *cbcls); - - -/** - * Notifies a tree that a connection it might be using is broken. - * Marks all peers down the paths as disconnected and notifies the client. - * - * @param t Tree to use. - * @param p1 Short id of one of the peers (order unimportant) - * @param p2 Short id of one of the peers (order unimportant) - * @param cb Function to call for every peer that is marked as disconnected. - * @param cbcls Closure for cb. - * - * @return Short ID of the first disconnected peer in the tree. - */ -GNUNET_PEER_Id -tree_notify_connection_broken (struct CadetTunnelTree *t, GNUNET_PEER_Id p1, - GNUNET_PEER_Id p2, CadetTreeCallback cb, - void *cbcls); - - -/** - * Deletes a peer from a tunnel, liberating all unused resources on the path to - * it. It shouldn't have children, if it has they will be destroyed as well. - * If the tree is not local and no longer has any paths, the root node will be - * destroyed and marked as NULL. - * - * FIXME: dont destroy the root - * - * @param t Tunnel tree to use. - * @param peer Short ID of the peer to remove from the tunnel tree. - * @param cb Callback to notify client of disconnected peers. - * @param cbcls Closure for cb. - * - * @return GNUNET_YES if the tunnel still has nodes - */ -int -tree_del_peer (struct CadetTunnelTree *t, GNUNET_PEER_Id peer, - CadetTreeCallback cb, void *cbcls); - - -/** - * Get the cost of the path relative to the already built tunnel tree - * - * @param t The tunnel tree to which compare - * @param path The individual path to reach a peer - * - * @return Number of hops to reach destination, UINT_MAX in case the peer is not - * in the path - */ -unsigned int -tree_get_path_cost (struct CadetTunnelTree *t, struct CadetPeerPath *path); - - -/** - * Print the tree on stderr - * - * @param t The tree - */ -void -tree_debug (struct CadetTunnelTree *t); - - -/** - * Destroy the whole tree and free all used memory and Peer_Ids - * - * @param t Tree to be destroyed - */ -void -tree_destroy (struct CadetTunnelTree *t); diff --git a/src/mesh/gnunet-cadet-profiler.c b/src/mesh/gnunet-cadet-profiler.c deleted file mode 100644 index c944caa75..000000000 --- a/src/mesh/gnunet-cadet-profiler.c +++ /dev/null @@ -1,1092 +0,0 @@ -/* - 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 cadet/gnunet-cadet-profiler.c - * - * @brief Profiler for cadet experiments. - */ -#include -#include "platform.h" -#include "cadet_test_lib.h" -#include "gnunet_cadet_service.h" -#include "gnunet_statistics_service.h" - - -#define PING 1 -#define PONG 2 - - -/** - * Paximum ping period in milliseconds. Real period = rand (0, PING_PERIOD) - */ -#define PING_PERIOD 1000 - -/** - * How long until we give up on connecting the peers? - */ -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) - -/** - * Time to wait for stuff that should be rather fast - */ -#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) - -/** - * Total number of rounds. - */ -#define number_rounds sizeof(rounds)/sizeof(rounds[0]) - -/** - * Ratio of peers active. First round always is 1.0. - */ -static float rounds[] = {0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.0}; - -/** - * Message type for pings. - */ -struct CadetPingMessage -{ - /** - * Header. Type PING/PONG. - */ - struct GNUNET_MessageHeader header; - - /** - * Message number. - */ - uint32_t counter; - - /** - * Time the message was sent. - */ - struct GNUNET_TIME_AbsoluteNBO timestamp; - - /** - * Round number. - */ - uint32_t round_number; -}; - -/** - * Peer description. - */ -struct CadetPeer -{ - /** - * Testbed Operation (to get peer id, etc). - */ - struct GNUNET_TESTBED_Operation *op; - - /** - * Peer ID. - */ - struct GNUNET_PeerIdentity id; - - /** - * Cadet handle for the root peer - */ - struct GNUNET_CADET_Handle *cadet; - - /** - * Channel handle for the root peer - */ - struct GNUNET_CADET_Channel *ch; - - /** - * Channel handle for the dest peer - */ - struct GNUNET_CADET_Channel *incoming_ch; - - /** - * Channel handle for a warmup channel. - */ - struct GNUNET_CADET_Channel *warmup_ch; - - /** - * Number of payload packes sent - */ - int data_sent; - - /** - * Number of payload packets received - */ - int data_received; - - /** - * Is peer up? - */ - int up; - - /** - * Destinaton to ping. - */ - struct CadetPeer *dest; - - /** - * Incoming channel for pings. - */ - struct CadetPeer *incoming; - - /** - * Task to do the next ping. - */ - GNUNET_SCHEDULER_TaskIdentifier ping_task; - - float mean[number_rounds]; - float var[number_rounds]; - unsigned int pongs[number_rounds]; - unsigned int pings[number_rounds]; - -}; - -/** - * Duration of each round. - */ -static struct GNUNET_TIME_Relative round_time; - -/** - * GNUNET_PeerIdentity -> CadetPeer - */ -static struct GNUNET_CONTAINER_MultiPeerMap *ids; - -/** - * Testbed peer handles. - */ -static struct GNUNET_TESTBED_Peer **testbed_handles; - -/** - * Testbed Operation (to get stats). - */ -static struct GNUNET_TESTBED_Operation *stats_op; - -/** - * Operation to get peer ids. - */ -struct CadetPeer *peers; - -/** - * Peer ids counter. - */ -static unsigned int p_ids; - -/** - * Total number of peers. - */ -static unsigned long long peers_total; - -/** - * Number of currently running peers. - */ -static unsigned long long peers_running; - -/** - * Number of peers doing pings. - */ -static unsigned long long peers_pinging; - -/** - * Test context (to shut down). - */ -static struct GNUNET_CADET_TEST_Context *test_ctx; - -/** - * Task called to shutdown test. - */ -static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; - -/** - * Task called to disconnect peers, before shutdown. - */ -static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; - -/** - * Task to perform tests - */ -static GNUNET_SCHEDULER_TaskIdentifier test_task; - -/** - * Round number. - */ -static unsigned int current_round; - -/** - * Do preconnect? (Each peer creates a tunnel to one other peer). - */ -static int do_warmup; - -/** - * Warmup progress. - */ -static unsigned int peers_warmup; - -/** - * Flag to notify callbacks not to generate any new traffic anymore. - */ -static int test_finished; - - -/** - * START THE TEST ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES. - * - * Testcase continues when the root receives confirmation of connected peers, - * on callback funtion ch. - * - * @param cls Closure (unsued). - * @param tc Task Context. - */ -static void -start_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - - -/** - * Calculate a random delay. - * - * @param max Exclusive maximum, in ms. - * - * @return A time between 0 a max-1 ms. - */ -static struct GNUNET_TIME_Relative -delay_ms_rnd (unsigned int max) -{ - unsigned int rnd; - - rnd = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, max); - return GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, rnd); -} - - -/** - * Get the index of a peer in the peers array. - * - * @param peer Peer whose index to get. - * - * @return Index of peer in peers. - */ -static unsigned int -get_index (struct CadetPeer *peer) -{ - return peer - peers; -} - - -/** - * Show the results of the test (banwidth acheived) and log them to GAUGER - */ -static void -show_end_data (void) -{ - struct CadetPeer *peer; - unsigned int i; - unsigned int j; - - for (i = 0; i < number_rounds; i++) - { - for (j = 0; j < peers_pinging; j++) - { - peer = &peers[j]; - FPRINTF (stdout, - "ROUND %3u PEER %3u: %10.2f / %10.2f, PINGS: %3u, PONGS: %3u\n", - i, j, peer->mean[i], sqrt (peer->var[i] / (peer->pongs[i] - 1)), - peer->pings[i], peer->pongs[i]); - } - } -} - - -/** - * Shut down peergroup, clean up. - * - * @param cls Closure (unused). - * @param tc Task Context. - */ -static void -shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Ending test.\n"); - shutdown_handle = GNUNET_SCHEDULER_NO_TASK; -} - - -/** - * Disconnect from cadet services af all peers, call shutdown. - * - * @param cls Closure (unused). - * @param tc Task Context. - */ -static void -disconnect_cadet_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - long line = (long) cls; - unsigned int i; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "disconnecting cadet service, called from line %ld\n", line); - disconnect_task = GNUNET_SCHEDULER_NO_TASK; - for (i = 0; i < peers_total; i++) - { - if (NULL != peers[i].op) - GNUNET_TESTBED_operation_done (peers[i].op); - - if (peers[i].up != GNUNET_YES) - continue; - - if (NULL != peers[i].ch) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u: channel %p\n", i, peers[i].ch); - GNUNET_CADET_channel_destroy (peers[i].ch); - } - if (NULL != peers[i].warmup_ch) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u: warmup channel %p\n", - i, peers[i].warmup_ch); - GNUNET_CADET_channel_destroy (peers[i].warmup_ch); - } - if (NULL != peers[i].incoming_ch) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u: incoming channel %p\n", - i, peers[i].incoming_ch); - GNUNET_CADET_channel_destroy (peers[i].incoming_ch); - } - } - GNUNET_CADET_TEST_cleanup (test_ctx); - if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle) - { - GNUNET_SCHEDULER_cancel (shutdown_handle); - } - shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); -} - - -/** - * Finish test normally: schedule disconnect and shutdown - * - * @param line Line in the code the abort is requested from (__LINE__). - */ -static void -abort_test (long line) -{ - if (disconnect_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (disconnect_task); - disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, - (void *) line); - } -} - -/** - * Stats callback. Finish the stats testbed operation and when all stats have - * been iterated, shutdown the test. - * - * @param cls closure - * @param op the operation that has been finished - * @param emsg error message in case the operation has failed; will be NULL if - * operation has executed successfully. - */ -static void -stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "... collecting statistics done.\n"); - GNUNET_TESTBED_operation_done (stats_op); - - if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) - GNUNET_SCHEDULER_cancel (disconnect_task); - disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, - (void *) __LINE__); - -} - - -/** - * Process statistic values. - * - * @param cls closure - * @param peer the peer the statistic belong to - * @param subsystem name of subsystem that created the statistic - * @param name the name of the datum - * @param value the current value - * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not - * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration - */ -static int -stats_iterator (void *cls, const struct GNUNET_TESTBED_Peer *peer, - const char *subsystem, const char *name, - uint64_t value, int is_persistent) -{ - uint32_t i; - - i = GNUNET_TESTBED_get_index (peer); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " STATS %u - %s [%s]: %llu\n", - i, subsystem, name, value); - - return GNUNET_OK; -} - - -/** - * Task check that keepalives were sent and received. - * - * @param cls Closure (NULL). - * @param tc Task Context. - */ -static void -collect_stats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0) - return; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Start collecting statistics...\n"); - stats_op = GNUNET_TESTBED_get_statistics (peers_total, testbed_handles, - NULL, NULL, - stats_iterator, stats_cont, NULL); -} - - -/** - * @brief Finish profiler normally. Signal finish and start collecting stats. - * - * @param cls Closure (unused). - * @param tc Task context. - */ -static void -finish_profiler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0) - return; - - test_finished = GNUNET_YES; - show_end_data(); - GNUNET_SCHEDULER_add_now (&collect_stats, NULL); -} - -/** - * Set the total number of running peers. - * - * @param target Desired number of running peers. - */ -static void -adjust_running_peers (unsigned int target) -{ - struct GNUNET_TESTBED_Operation *op; - unsigned int delta; - unsigned int run; - unsigned int i; - unsigned int r; - - GNUNET_assert (target <= peers_total); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "adjust peers to %u\n", target); - if (target > peers_running) - { - delta = target - peers_running; - run = GNUNET_YES; - } - else - { - delta = peers_running - target; - run = GNUNET_NO; - } - - for (i = 0; i < delta; i++) - { - do { - r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, - peers_total - peers_pinging); - r += peers_pinging; - } while (peers[r].up == run || NULL != peers[r].incoming); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "St%s peer %u: %s\n", - run ? "arting" : "opping", r, GNUNET_i2s (&peers[r].id)); - - if (GNUNET_SCHEDULER_NO_TASK != peers[r].ping_task) - GNUNET_SCHEDULER_cancel (peers[r].ping_task); - peers[r].ping_task = GNUNET_SCHEDULER_NO_TASK; - - peers[r].up = run; - - if (NULL != peers[r].ch) - GNUNET_CADET_channel_destroy (peers[r].ch); - peers[r].ch = NULL; - if (NULL != peers[r].dest) - { - if (NULL != peers[r].dest->incoming_ch) - GNUNET_CADET_channel_destroy (peers[r].dest->incoming_ch); - peers[r].dest->incoming_ch = NULL; - } - - op = GNUNET_TESTBED_peer_manage_service (&peers[r], testbed_handles[r], - "cadet", NULL, NULL, run); - GNUNET_break (NULL != op); - peers_running += run ? 1 : -1; - GNUNET_assert (peers_running > 0); - } -} - - -/** - * @brief Move to next round. - * - * @param cls Closure (round #). - * @param tc Task context. - */ -static void -next_rnd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0) - return; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "ROUND %ld\n", current_round); - if (0.0 == rounds[current_round]) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Finishing\n"); - GNUNET_SCHEDULER_add_now (&finish_profiler, NULL); - return; - } - adjust_running_peers (rounds[current_round] * peers_total); - current_round++; - - GNUNET_SCHEDULER_add_delayed (round_time, &next_rnd, NULL); -} - - -/** - * Transmit ping callback. - * - * @param cls Closure (peer for PING, NULL for PONG). - * @param size Size of the tranmist buffer. - * @param buf Pointer to the beginning of the buffer. - * - * @return Number of bytes written to buf. - */ -static size_t -tmt_rdy_ping (void *cls, size_t size, void *buf); - - -/** - * Transmit pong callback. - * - * @param cls Closure (copy of PING message, to be freed). - * @param size Size of the buffer we have. - * @param buf Buffer to copy data to. - */ -static size_t -tmt_rdy_pong (void *cls, size_t size, void *buf) -{ - struct CadetPingMessage *ping = cls; - struct CadetPingMessage *pong; - - if (0 == size || NULL == buf) - { - GNUNET_free (ping); - return 0; - } - pong = (struct CadetPingMessage *) buf; - memcpy (pong, ping, sizeof (*ping)); - pong->header.type = htons (PONG); - - GNUNET_free (ping); - return sizeof (*ping); -} - - -/** - * @brief Send a ping to destination - * - * @param cls Closure (peer). - * @param tc Task context. - */ -static void -ping (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct CadetPeer *peer = (struct CadetPeer *) cls; - - peer->ping_task = GNUNET_SCHEDULER_NO_TASK; - - if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0 - || GNUNET_YES == test_finished) - return; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u -> %u (%u)\n", - get_index (peer), get_index (peer->dest), peer->data_sent); - - GNUNET_CADET_notify_transmit_ready (peer->ch, GNUNET_NO, - GNUNET_TIME_UNIT_FOREVER_REL, - sizeof (struct CadetPingMessage), - &tmt_rdy_ping, peer); -} - -/** - * @brief Reply with a pong to origin. - * - * @param cls Closure (peer). - * @param tc Task context. - */ -static void -pong (struct GNUNET_CADET_Channel *channel, const struct CadetPingMessage *ping) -{ - struct CadetPingMessage *copy; - - copy = GNUNET_new (struct CadetPingMessage); - memcpy (copy, ping, sizeof (*ping)); - GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO, - GNUNET_TIME_UNIT_FOREVER_REL, - sizeof (struct CadetPingMessage), - &tmt_rdy_pong, copy); -} - - -/** - * Transmit ping callback - * - * @param cls Closure (peer). - * @param size Size of the buffer we have. - * @param buf Buffer to copy data to. - */ -static size_t -tmt_rdy_ping (void *cls, size_t size, void *buf) -{ - struct CadetPeer *peer = (struct CadetPeer *) cls; - struct CadetPingMessage *msg = buf; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tmt_rdy called, filling buffer\n"); - if (size < sizeof (struct CadetPingMessage) || NULL == buf) - { - GNUNET_break (GNUNET_YES == test_finished); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "size %u, buf %p, data_sent %u, data_received %u\n", - size, buf, peer->data_sent, peer->data_received); - - return 0; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending: msg %d\n", peer->data_sent); - msg->header.size = htons (size); - msg->header.type = htons (PING); - msg->counter = htonl (peer->data_sent++); - msg->round_number = htonl (current_round); - msg->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); - peer->pings[current_round]++; - peer->ping_task = GNUNET_SCHEDULER_add_delayed (delay_ms_rnd (PING_PERIOD), - &ping, peer); - - return sizeof (struct CadetPingMessage); -} - - -/** - * Function is called whenever a PING message is received. - * - * @param cls closure (peer #, set from GNUNET_CADET_connect) - * @param channel connection to the other end - * @param channel_ctx place to store local state associated with the channel - * @param message the actual message - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -int -ping_handler (void *cls, struct GNUNET_CADET_Channel *channel, - void **channel_ctx, - const struct GNUNET_MessageHeader *message) -{ - long n = (long) cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%u got PING\n", n); - GNUNET_CADET_receive_done (channel); - if (GNUNET_NO == test_finished) - pong (channel, (struct CadetPingMessage *) message); - - return GNUNET_OK; -} - - -/** - * Function is called whenever a PONG message is received. - * - * @param cls closure (peer #, set from GNUNET_CADET_connect) - * @param channel connection to the other end - * @param channel_ctx place to store local state associated with the channel - * @param message the actual message - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -int -pong_handler (void *cls, struct GNUNET_CADET_Channel *channel, - void **channel_ctx, - const struct GNUNET_MessageHeader *message) -{ - long n = (long) cls; - struct CadetPeer *peer; - struct CadetPingMessage *msg; - struct GNUNET_TIME_Absolute send_time; - struct GNUNET_TIME_Relative latency; - unsigned int r /* Ping round */; - float delta; - - GNUNET_CADET_receive_done (channel); - peer = &peers[n]; - - msg = (struct CadetPingMessage *) message; - - send_time = GNUNET_TIME_absolute_ntoh (msg->timestamp); - latency = GNUNET_TIME_absolute_get_duration (send_time); - r = ntohl (msg->round_number); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u <- %u (%u) latency: %s\n", - get_index (peer), get_index (peer->dest), ntohl (msg->counter), - GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO)); - - /* Online variance calculation */ - peer->pongs[r]++; - delta = latency.rel_value_us - peer->mean[r]; - peer->mean[r] = peer->mean[r] + delta/peer->pongs[r]; - peer->var[r] += delta * (latency.rel_value_us - peer->mean[r]); - - return GNUNET_OK; -} - - -/** - * Handlers, for diverse services - */ -static struct GNUNET_CADET_MessageHandler handlers[] = { - {&ping_handler, PING, sizeof (struct CadetPingMessage)}, - {&pong_handler, PONG, sizeof (struct CadetPingMessage)}, - {NULL, 0, 0} -}; - - -/** - * Method called whenever another peer has added us to a channel - * the other peer initiated. - * - * @param cls Closure. - * @param channel New handle to the channel. - * @param initiator Peer that started the channel. - * @param port Port this channel is connected to. - * @param options channel option flags - * @return Initial channel context for the channel - * (can be NULL -- that's not an error). - */ -static void * -incoming_channel (void *cls, struct GNUNET_CADET_Channel *channel, - const struct GNUNET_PeerIdentity *initiator, - uint32_t port, enum GNUNET_CADET_ChannelOption options) -{ - long n = (long) cls; - struct CadetPeer *peer; - - peer = GNUNET_CONTAINER_multipeermap_get (ids, initiator); - GNUNET_assert (NULL != peer); - if (NULL == peers[n].incoming) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "WARMUP %3u: %u <= %u\n", - peers_warmup, n, get_index (peer)); - peers_warmup++; - if (peers_warmup < peers_total) - return NULL; - if (GNUNET_SCHEDULER_NO_TASK != test_task) - { - GNUNET_SCHEDULER_cancel (test_task); - test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, - &start_test, NULL); - } - return NULL; - } - GNUNET_assert (peer == peers[n].incoming); - GNUNET_assert (peer->dest == &peers[n]); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u <= %u %p\n", - n, get_index (peer), channel); - peers[n].incoming_ch = channel; - - return NULL; -} - -/** - * Function called whenever an inbound channel is destroyed. Should clean up - * any associated state. - * - * @param cls closure (set from GNUNET_CADET_connect) - * @param channel connection to the other end (henceforth invalid) - * @param channel_ctx place where local state associated - * with the channel is stored - */ -static void -channel_cleaner (void *cls, const struct GNUNET_CADET_Channel *channel, - void *channel_ctx) -{ - long n = (long) cls; - struct CadetPeer *peer = &peers[n]; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Channel %p disconnected at peer %ld\n", channel, n); - if (peer->ch == channel) - peer->ch = NULL; -} - - -/** - * Select a random peer that has no incoming channel - * - * @param peer ID of the peer connecting. NULL if irrelevant (warmup). - * - * @return Random peer not yet connected to. - */ -static struct CadetPeer * -select_random_peer (struct CadetPeer *peer) -{ - unsigned int r; - - do - { - r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, peers_total); - } while (NULL != peers[r].incoming); - peers[r].incoming = peer; - - return &peers[r]; -} - -/** - * START THE TEST ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES. - * - * Testcase continues when the root receives confirmation of connected peers, - * on callback funtion ch. - * - * @param cls Closure (unsued). - * @param tc Task Context. - */ -static void -start_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - enum GNUNET_CADET_ChannelOption flags; - unsigned long i; - - test_task = GNUNET_SCHEDULER_NO_TASK; - if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0) - return; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Start profiler\n"); - - flags = GNUNET_CADET_OPTION_DEFAULT; - for (i = 0; i < peers_pinging; i++) - { - peers[i].dest = select_random_peer (&peers[i]); - peers[i].ch = GNUNET_CADET_channel_create (peers[i].cadet, NULL, - &peers[i].dest->id, - 1, flags); - if (NULL == peers[i].ch) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Channel %lu failed\n", i); - GNUNET_CADET_TEST_cleanup (test_ctx); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u => %u %p\n", - i, get_index (peers[i].dest), peers[i].ch); - peers[i].ping_task = GNUNET_SCHEDULER_add_delayed (delay_ms_rnd (2000), - &ping, &peers[i]); - } - peers_running = peers_total; - if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) - GNUNET_SCHEDULER_cancel (disconnect_task); - disconnect_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(round_time, - number_rounds + 1), - &disconnect_cadet_peers, - (void *) __LINE__); - GNUNET_SCHEDULER_add_delayed (round_time, &next_rnd, NULL); -} - - -/** - * Do warmup: create some channels to spread information about the topology. - */ -static void -warmup (void) -{ - struct CadetPeer *peer; - unsigned int i; - - for (i = 0; i < peers_total; i++) - { - peer = select_random_peer (NULL); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "WARMUP %u => %u\n", - i, get_index (peer)); - peers[i].warmup_ch = - GNUNET_CADET_channel_create (peers[i].cadet, NULL, &peer->id, - 1, GNUNET_CADET_OPTION_DEFAULT); - if (NULL == peers[i].warmup_ch) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Warmup %u failed\n", i); - GNUNET_CADET_TEST_cleanup (test_ctx); - return; - } - } -} - -/** - * Callback to be called when the requested peer information is available - * - * @param cls the closure from GNUNET_TESTBED_peer_get_information() - * @param op the operation this callback corresponds to - * @param pinfo the result; will be NULL if the operation has failed - * @param emsg error message if the operation has failed; - * NULL if the operation is successfull - */ -static void -peer_id_cb (void *cls, - struct GNUNET_TESTBED_Operation *op, - const struct GNUNET_TESTBED_PeerInformation *pinfo, - const char *emsg) -{ - long n = (long) cls; - - if (NULL == pinfo || NULL != emsg) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg); - abort_test (__LINE__); - return; - } - peers[n].id = *(pinfo->result.id); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, " %u id: %s\n", - n, GNUNET_i2s (&peers[n].id)); - GNUNET_break (GNUNET_OK == - GNUNET_CONTAINER_multipeermap_put (ids, &peers[n].id, &peers[n], - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); - - GNUNET_TESTBED_operation_done (peers[n].op); - peers[n].op = NULL; - - p_ids++; - if (p_ids < peers_total) - return; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got all IDs, starting profiler\n"); - if (do_warmup) - { - struct GNUNET_TIME_Relative delay; - - warmup(); - delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, - 100 * peers_total); - test_task = GNUNET_SCHEDULER_add_delayed (delay, &start_test, NULL); - return; /* start_test from incoming_channel */ - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Starting in a second...\n"); - test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, - &start_test, NULL); -} - -/** - * test main: start test when all peers are connected - * - * @param cls Closure. - * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end. - * @param num_peers Number of peers that are running. - * @param testbed_peers Array of peers. - * @param cadetes Handle to each of the CADETs of the peers. - */ -static void -tmain (void *cls, - struct GNUNET_CADET_TEST_Context *ctx, - unsigned int num_peers, - struct GNUNET_TESTBED_Peer **testbed_peers, - struct GNUNET_CADET_Handle **cadetes) -{ - unsigned long i; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n"); - test_ctx = ctx; - GNUNET_assert (peers_total == num_peers); - peers_running = num_peers; - testbed_handles = testbed_peers; - disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, - &disconnect_cadet_peers, - (void *) __LINE__); - shutdown_handle = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, - &shutdown_task, NULL); - for (i = 0; i < peers_total; i++) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requesting id %ld\n", i); - peers[i].up = GNUNET_YES; - peers[i].cadet = cadetes[i]; - peers[i].op = - GNUNET_TESTBED_peer_get_information (testbed_handles[i], - GNUNET_TESTBED_PIT_IDENTITY, - &peer_id_cb, (void *) i); - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "requested peer ids\n"); - /* Continues from pi_cb -> do_test */ -} - - -/** - * Main: start profiler. - */ -int -main (int argc, char *argv[]) -{ - static uint32_t ports[2]; - const char *config_file; - - config_file = ".profiler.conf"; - - if (4 > argc) - { - fprintf (stderr, "usage: %s ROUND_TIME PEERS PINGS [DO_WARMUP]\n", argv[0]); - fprintf (stderr, "example: %s 30s 16 1 Y\n", argv[0]); - return 1; - } - - if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_relative (argv[1], &round_time)) - { - fprintf (stderr, "%s is not a valid time\n", argv[1]); - return 1; - } - - peers_total = atoll (argv[2]); - if (2 > peers_total) - { - fprintf (stderr, "%s peers is not valid (> 2)\n", argv[1]); - return 1; - } - peers = GNUNET_malloc (sizeof (struct CadetPeer) * peers_total); - - peers_pinging = atoll (argv[3]); - - if (peers_total < 2 * peers_pinging) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "not enough peers, total should be > 2 * peers_pinging\n"); - return 1; - } - - do_warmup = (5 > argc || argv[4][0] != 'N'); - - ids = GNUNET_CONTAINER_multipeermap_create (2 * peers_total, GNUNET_YES); - GNUNET_assert (NULL != ids); - p_ids = 0; - test_finished = GNUNET_NO; - ports[0] = 1; - ports[1] = 0; - GNUNET_CADET_TEST_run ("cadet-profiler", config_file, peers_total, - &tmain, NULL, /* tmain cls */ - &incoming_channel, &channel_cleaner, - handlers, ports); - GNUNET_free (peers); - - return 0; -} - -/* end of gnunet-cadet-profiler.c */ - diff --git a/src/mesh/gnunet-cadet.c b/src/mesh/gnunet-cadet.c deleted file mode 100644 index 840c6d0ac..000000000 --- a/src/mesh/gnunet-cadet.c +++ /dev/null @@ -1,851 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2012 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 cadet/gnunet-cadet.c - * @brief Print information about cadet tunnels and peers. - * @author Bartlomiej Polot - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_cadet_service.h" -#include "cadet.h" - - -/** - * Option -m. - */ -static int monitor_connections; - -/** - * Option -P. - */ -static int request_peers; - -/** - * Option --peer - */ -static char *peer_id; - -/** - * Option -T. - */ -static int request_tunnels; - -/** - * Option --tunnel - */ -static char *tunnel_id; - -/** - * Option --connection - */ -static char *conn_id; - -/** - * Option --channel - */ -static char *channel_id; - -/** - * Port to listen on (-p). - */ -static uint32_t listen_port; - -/** - * Request echo service - */ -int echo; - -/** - * Time of last echo request. - */ -struct GNUNET_TIME_Absolute echo_time; - -/** - * Task for next echo request. - */ -GNUNET_SCHEDULER_TaskIdentifier echo_task; - -/** - * Peer to connect to. - */ -static char *target_id; - -/** - * Port to connect to - */ -static uint32_t target_port; - -/** - * Data pending in netcat mode. - */ -size_t data_size; - - -/** - * Cadet handle. - */ -static struct GNUNET_CADET_Handle *mh; - -/** - * Channel handle. - */ -static struct GNUNET_CADET_Channel *ch; - -/** - * Shutdown task handle. - */ -GNUNET_SCHEDULER_TaskIdentifier sd; - - - -static void -listen_stdio (void); - - - -/** - * Task run in monitor mode when the user presses CTRL-C to abort. - * Stops monitoring activity. - * - * @param cls Closure (unused). - * @param tc scheduler context - */ -static void -shutdown_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n"); - if (NULL != ch) - { - GNUNET_CADET_channel_destroy (ch); - ch = NULL; - } - if (NULL != mh) - { - GNUNET_CADET_disconnect (mh); - mh = NULL; - } -} - - -/** - * Function called to notify a client about the connection - * begin ready to queue more data. "buf" will be - * NULL and "size" zero if the connection was closed for - * writing in the meantime. - * - * FIXME - * - * @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 - */ -size_t -data_ready (void *cls, size_t size, void *buf) -{ - struct GNUNET_MessageHeader *msg; - size_t total_size; - - if (NULL == buf || 0 == size) - { - GNUNET_SCHEDULER_shutdown(); - return 0; - } - - total_size = data_size + sizeof (struct GNUNET_MessageHeader); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending %u bytes\n", data_size); - GNUNET_assert (size >= total_size); - - msg = buf; - msg->size = htons (total_size); - msg->type = htons (GNUNET_MESSAGE_TYPE_CADET_CLI); - memcpy (&msg[1], cls, data_size); - if (GNUNET_NO == echo) - { - listen_stdio (); - } - else - { - echo_time = GNUNET_TIME_absolute_get (); - } - - return total_size; -} - - -/** - * Task run in monitor mode when the user presses CTRL-C to abort. - * Stops monitoring activity. - * - * @param cls Closure (unused). - * @param tc scheduler context - */ -static void -read_stdio (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - static char buf[60000]; - - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - { - return; - } - - data_size = read (0, buf, 60000); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "stdio read %u bytes\n", data_size); - if (data_size < 1) - { - GNUNET_SCHEDULER_shutdown(); - return; - } - GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO, - GNUNET_TIME_UNIT_FOREVER_REL, - data_size - + sizeof (struct GNUNET_MessageHeader), - &data_ready, buf); -} - - -/** - * Start listening to stdin - */ -static void -listen_stdio (void) -{ - struct GNUNET_NETWORK_FDSet *rs; - - rs = GNUNET_NETWORK_fdset_create (); - GNUNET_NETWORK_fdset_set_native (rs, 0); - GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_TIME_UNIT_FOREVER_REL, - rs, NULL, - &read_stdio, NULL); - GNUNET_NETWORK_fdset_destroy (rs); -} - - -/** - * Function called whenever a channel is destroyed. Should clean up - * any associated state. - * - * It must NOT call #GNUNET_CADET_channel_destroy on the channel. - * - * @param cls closure (set from #GNUNET_CADET_connect) - * @param channel connection to the other end (henceforth invalid) - * @param channel_ctx place where local state associated - * with the channel is stored - */ -static void -channel_ended (void *cls, - const struct GNUNET_CADET_Channel *channel, - void *channel_ctx) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel ended!\n"); - GNUNET_break (channel == ch); - ch = NULL; - GNUNET_SCHEDULER_shutdown (); -} - - -/** - * Method called whenever another peer has added us to a channel - * the other peer initiated. - * Only called (once) upon reception of data with a message type which was - * subscribed to in #GNUNET_CADET_connect. - * - * A call to #GNUNET_CADET_channel_destroy causes te channel to be ignored. In - * this case the handler MUST return NULL. - * - * @param cls closure - * @param channel new handle to the channel - * @param initiator peer that started the channel - * @param port Port this channel is for. - * @param options CadetOption flag field, with all active option bits set to 1. - * - * @return initial channel context for the channel - * (can be NULL -- that's not an error) - */ -static void * -channel_incoming (void *cls, - struct GNUNET_CADET_Channel * channel, - const struct GNUNET_PeerIdentity * initiator, - uint32_t port, enum GNUNET_CADET_ChannelOption options) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Incoming channel %p on port %u\n", - channel, port); - if (NULL != ch) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "A channel already exists\n"); - return NULL; - } - if (0 == listen_port) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not listening to channels\n"); - return NULL; - } - ch = channel; - if (GNUNET_NO == echo) - { - listen_stdio (); - return NULL; - } - data_size = 0; - return NULL; -} - -/** - * @brief Send an echo request to the remote peer. - * - * @param cls Closure (NULL). - * @param tc Task context. - */ -static void -send_echo (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) || NULL == ch) - return; - - GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO, - GNUNET_TIME_UNIT_FOREVER_REL, - sizeof (struct GNUNET_MessageHeader), - &data_ready, NULL); -} - - - -/** - * Call CADET's monitor API, get info of one connection. - * - * @param cls Closure (unused). - * @param tc TaskContext - */ -static void -create_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_PeerIdentity pid; - enum GNUNET_CADET_ChannelOption opt; - - GNUNET_assert (NULL == ch); - - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_public_key_from_string (target_id, - strlen (target_id), - &pid.public_key)) - { - FPRINTF (stderr, - _("Invalid target `%s'\n"), - target_id); - GNUNET_SCHEDULER_shutdown (); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to `%s'\n", target_id); - opt = GNUNET_CADET_OPTION_DEFAULT | GNUNET_CADET_OPTION_RELIABLE; - ch = GNUNET_CADET_channel_create (mh, NULL, &pid, target_port, opt); - if (GNUNET_NO == echo) - listen_stdio (); - else - GNUNET_SCHEDULER_add_now (send_echo, NULL); -} - - -/** - * Function called whenever a message is received. - * - * Each time the function must call #GNUNET_CADET_receive_done on the channel - * in order to receive the next message. This doesn't need to be immediate: - * can be delayed if some processing is done on the message. - * - * @param cls Closure (set from #GNUNET_CADET_connect). - * @param channel Connection to the other end. - * @param channel_ctx Place to store local state associated with the channel. - * @param message The actual message. - * @return #GNUNET_OK to keep the channel open, - * #GNUNET_SYSERR to close it (signal serious error). - */ -static int -data_callback (void *cls, - struct GNUNET_CADET_Channel *channel, - void **channel_ctx, - const struct GNUNET_MessageHeader *message) -{ - uint16_t len; - ssize_t done; - uint16_t off; - const char *buf; - GNUNET_break (ch == channel); - - if (GNUNET_YES == echo) - { - if (0 != listen_port) - { - /* Just listening to echo incoming messages*/ - GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO, - GNUNET_TIME_UNIT_FOREVER_REL, - sizeof (struct GNUNET_MessageHeader), - &data_ready, NULL); - return GNUNET_OK; - } - else - { - struct GNUNET_TIME_Relative latency; - - latency = GNUNET_TIME_absolute_get_duration (echo_time); - echo_time = GNUNET_TIME_UNIT_FOREVER_ABS; - FPRINTF (stdout, "time: %s\n", - GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO)); - echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, - &send_echo, NULL); - } - } - - len = ntohs (message->size) - sizeof (*message); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u bytes\n", len); - buf = (const char *) &message[1]; - off = 0; - while (off < len) - { - done = write (1, &buf[off], len - off); - if (done <= 0) - { - if (-1 == done) - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, - "write"); - return GNUNET_SYSERR; - } - off += done; - } - return GNUNET_OK; -} - - -/** - * Method called to retrieve information about all peers in CADET, called - * once per peer. - * - * After last peer has been reported, an additional call with NULL is done. - * - * @param cls Closure. - * @param peer Peer, or NULL on "EOF". - * @param tunnel Do we have a tunnel towards this peer? - * @param n_paths Number of known paths towards this peer. - * @param best_path How long is the best path? - * (0 = unknown, 1 = ourselves, 2 = neighbor) - */ -static void -peers_callback (void *cls, const struct GNUNET_PeerIdentity *peer, - int tunnel, unsigned int n_paths, unsigned int best_path) -{ - if (NULL == peer) - { - if (GNUNET_YES != monitor_connections) - { - GNUNET_SCHEDULER_shutdown(); - } - return; - } - FPRINTF (stdout, "%s tunnel: %c, paths: %u\n", - GNUNET_i2s_full (peer), tunnel ? 'Y' : 'N', n_paths); -} - -/** - * Method called to retrieve information about a specific peer - * known to the service. - * - * @param cls Closure. - * @param peer Peer ID. - * @param tunnel Do we have a tunnel towards this peer? #GNUNET_YES/#GNUNET_NO - * @param neighbor Is this a direct neighbor? #GNUNET_YES/#GNUNET_NO - * @param n_paths Number of paths known towards peer. - * @param paths Array of PEER_IDs representing all paths to reach the peer. - * Each path starts with the local peer. - * Each path ends with the destination peer (given in @c peer). - */ -void -peer_callback (void *cls, - const struct GNUNET_PeerIdentity *peer, - int tunnel, - int neighbor, - unsigned int n_paths, - struct GNUNET_PeerIdentity *paths) -{ -} - - -/** - * Method called to retrieve information about all tunnels in CADET. - * - * @param cls Closure. - * @param peer Destination peer. - * @param channels Number of channels. - * @param connections Number of connections. - * @param estate Encryption state. - * @param cstate Connectivity state. - */ -void -tunnels_callback (void *cls, - const struct GNUNET_PeerIdentity *peer, - unsigned int channels, - unsigned int connections, - uint16_t estate, - uint16_t cstate) -{ - if (NULL == peer) - { - if (GNUNET_YES != monitor_connections) - { - GNUNET_SCHEDULER_shutdown(); - } - return; - } - FPRINTF (stdout, "%s [ENC: %u, CON: %u] CHs: %u, CONNs: %u\n", - GNUNET_i2s_full (peer), estate, cstate, channels, connections); -} - - -/** - * Method called to retrieve information about a specific tunnel the cadet peer - * has established, o`r is trying to establish. - * - * @param cls Closure. - * @param peer Peer towards whom the tunnel is directed. - * @param n_channels Number of channels. - * @param n_connections Number of connections. - * @param channels Channels. - * @param connections Connections. - * @param estate Encryption status. - * @param cstate Connectivity status. - */ -void -tunnel_callback (void *cls, - const struct GNUNET_PeerIdentity *peer, - unsigned int n_channels, - unsigned int n_connections, - uint32_t *channels, - struct GNUNET_CADET_Hash *connections, - unsigned int estate, - unsigned int cstate) -{ - unsigned int i; - - if (NULL != peer) - { - FPRINTF (stdout, "Tunnel %s\n", GNUNET_i2s_full (peer)); - FPRINTF (stdout, "- %u channels\n", n_channels); - for (i = 0; i < n_channels; i++) - FPRINTF (stdout, " %u\n", channels[i]); - FPRINTF (stdout, "- %u connections\n", n_connections); - for (i = 0; i < n_connections; i++) - FPRINTF (stdout, " %s\n", GM_h2s (&connections[i])); - FPRINTF (stdout, "- enc state: %u\n", estate); - FPRINTF (stdout, "- con state: %u\n", cstate); - } - if (GNUNET_YES != monitor_connections) - { - GNUNET_SCHEDULER_shutdown(); - } - return; - -} - - -/** - * Call CADET's meta API, get all peers known to a peer. - * - * @param cls Closure (unused). - * @param tc TaskContext - */ -static void -get_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n"); - return; - } - GNUNET_CADET_get_peers (mh, &peers_callback, NULL); -} - - -/** - * Call CADET's monitor API, get info of one peer. - * - * @param cls Closure (unused). - * @param tc TaskContext - */ -static void -show_peer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_PeerIdentity pid; - - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id, - strlen (peer_id), - &pid.public_key)) - { - fprintf (stderr, - _("Invalid peer ID `%s'\n"), - peer_id); - GNUNET_SCHEDULER_shutdown(); - return; - } - GNUNET_CADET_get_peer (mh, &pid, peer_callback, NULL); -} - -/** - * Call CADET's meta API, get all tunnels known to a peer. - * - * @param cls Closure (unused). - * @param tc TaskContext - */ -static void -get_tunnels (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n"); - return; - } - GNUNET_CADET_get_tunnels (mh, &tunnels_callback, NULL); -} - - -/** - * Call CADET's monitor API, get info of one tunnel. - * - * @param cls Closure (unused). - * @param tc TaskContext - */ -static void -show_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_PeerIdentity pid; - - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_public_key_from_string (tunnel_id, - strlen (tunnel_id), - &pid.public_key)) - { - fprintf (stderr, - _("Invalid tunnel owner `%s'\n"), - tunnel_id); - GNUNET_SCHEDULER_shutdown(); - return; - } - GNUNET_CADET_get_tunnel (mh, &pid, tunnel_callback, NULL); -} - - -/** - * Call CADET's monitor API, get info of one channel. - * - * @param cls Closure (unused). - * @param tc TaskContext - */ -static void -show_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - -} - - -/** - * Call CADET's monitor API, get info of one connection. - * - * @param cls Closure (unused). - * @param tc TaskContext - */ -static void -show_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - -} - - -/** - * 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) -{ - GNUNET_CADET_InboundChannelNotificationHandler *newch = NULL; - GNUNET_CADET_ChannelEndHandler *endch = NULL; - static const struct GNUNET_CADET_MessageHandler handlers[] = { - {&data_callback, GNUNET_MESSAGE_TYPE_CADET_CLI, 0}, - {NULL, 0, 0} /* FIXME add option to monitor msg types */ - }; - static uint32_t *ports = NULL; - /* FIXME add option to monitor apps */ - - target_id = args[0]; - target_port = args[0] && args[1] ? atoi(args[1]) : 0; - if ( (0 != (request_peers | request_tunnels) - || 0 != monitor_connections - || NULL != tunnel_id - || NULL != conn_id - || NULL != channel_id) - && target_id != NULL) - { - FPRINTF (stderr, - _("You must NOT give a TARGET" - "when using 'request all' options\n")); - return; - } - - if (NULL != target_id) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating channel to %s\n", - target_id); - GNUNET_SCHEDULER_add_now (&create_channel, NULL); - endch = &channel_ended; - } - else if (0 != listen_port) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Listen\n"); - newch = &channel_incoming; - endch = &channel_ended; - ports = GNUNET_malloc (sizeof (uint32_t) * 2); - ports[0] = listen_port; - } - else if (NULL != peer_id) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show peer\n"); - GNUNET_SCHEDULER_add_now (&show_peer, NULL); - } - else if (NULL != tunnel_id) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show tunnel\n"); - GNUNET_SCHEDULER_add_now (&show_tunnel, NULL); - } - else if (NULL != channel_id) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show channel\n"); - GNUNET_SCHEDULER_add_now (&show_channel, NULL); - } - else if (NULL != conn_id) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show connection\n"); - GNUNET_SCHEDULER_add_now (&show_connection, NULL); - } - else if (GNUNET_YES == request_peers) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all peers\n"); - GNUNET_SCHEDULER_add_now (&get_peers, NULL); - } - else if (GNUNET_YES == request_tunnels) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all tunnels\n"); - GNUNET_SCHEDULER_add_now (&get_tunnels, NULL); - } - else - { - FPRINTF (stderr, "No action requested\n"); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to cadet\n"); - mh = GNUNET_CADET_connect (cfg, - NULL, /* cls */ - newch, /* new channel */ - endch, /* cleaner */ - handlers, - ports); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done\n"); - if (NULL == mh) - GNUNET_SCHEDULER_add_now (shutdown_task, NULL); - else - sd = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, - shutdown_task, NULL); - -} - - -/** - * The main function to obtain peer information. - * - * @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) -{ - int res; - const char helpstr[] = "Create channels and retreive info about cadets status."; - static const struct GNUNET_GETOPT_CommandLineOption options[] = { -// {'a', "channel", "TUNNEL_ID:CHANNEL_ID", -// gettext_noop ("provide information about a particular channel"), -// GNUNET_YES, &GNUNET_GETOPT_set_string, &channel_id}, - {'C', "connection", "CONNECTION_ID", - gettext_noop ("provide information about a particular connection"), - GNUNET_YES, &GNUNET_GETOPT_set_string, &conn_id}, - {'e', "echo", NULL, - gettext_noop ("activate echo mode"), - GNUNET_NO, &GNUNET_GETOPT_set_one, &echo}, -// {'m', "monitor", NULL, -// gettext_noop ("provide information about all events (continuously)"), -// GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor_mode}, - {'o', "open-port", NULL, - gettext_noop ("port to listen to (default; 0)"), - GNUNET_YES, &GNUNET_GETOPT_set_uint, &listen_port}, - {'p', "peer", "PEER_ID", - gettext_noop ("provide information about a patricular peer"), - GNUNET_YES, &GNUNET_GETOPT_set_string, &peer_id}, - {'P', "peers", NULL, - gettext_noop ("provide information about all peers"), - GNUNET_NO, &GNUNET_GETOPT_set_one, &request_peers}, - {'t', "tunnel", "TUNNEL_ID", - gettext_noop ("provide information about a particular tunnel"), - GNUNET_YES, &GNUNET_GETOPT_set_string, &tunnel_id}, - {'T', "tunnels", NULL, - gettext_noop ("provide information about all tunnels"), - GNUNET_NO, &GNUNET_GETOPT_set_one, &request_tunnels}, - - GNUNET_GETOPT_OPTION_END - }; - - monitor_connections = GNUNET_NO; - - if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) - return 2; - - res = GNUNET_PROGRAM_run (argc, argv, "gnunet-cadet (OPTIONS | TARGET PORT)", - gettext_noop (helpstr), - options, &run, NULL); - - GNUNET_free ((void *) argv); - - if (GNUNET_OK == res) - return 0; - else - return 1; -} - -/* end of gnunet-cadet.c */ diff --git a/src/mesh/gnunet-service-cadet.c b/src/mesh/gnunet-service-cadet.c deleted file mode 100644 index de9aaf7a5..000000000 --- a/src/mesh/gnunet-service-cadet.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2001-2013 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 cadet/gnunet-service-cadet.c - * @brief GNUnet CADET service with encryption - * @author Bartlomiej Polot - * - * FIXME in progress: - * - rekey - reliability interaction - * - channel retransmit timing - * - * TODO: - * - relay corking down to core - * - set ttl relative to path length - * TODO END - * - * Dictionary: - * - peer: other cadet instance. If there is direct connection it's a neighbor. - * - tunnel: encrypted connection to a peer, neighbor or not. - * - channel: connection between two clients, on the same or different peers. - * have properties like reliability. - * - path: series of directly connected peer from one peer to another. - * - connection: path which is being used in a tunnel. - */ - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "cadet.h" -#include "gnunet_statistics_service.h" - -#include "gnunet-service-cadet_local.h" -#include "gnunet-service-cadet_channel.h" -#include "gnunet-service-cadet_connection.h" -#include "gnunet-service-cadet_tunnel.h" -#include "gnunet-service-cadet_dht.h" -#include "gnunet-service-cadet_peer.h" -#include "gnunet-service-cadet_hello.h" - - -/******************************************************************************/ -/*********************** GLOBAL VARIABLES ****************************/ -/******************************************************************************/ - -/****************************** Global variables ******************************/ - -/** - * Handle to the statistics service. - */ -struct GNUNET_STATISTICS_Handle *stats; - -/** - * Local peer own ID (memory efficient handle). - */ -GNUNET_PEER_Id myid; - -/** - * Local peer own ID (full value). - */ -struct GNUNET_PeerIdentity my_full_id; - - -/** - * Signal that shutdown is happening: prevent recover measures. - */ -int shutting_down; - -/*************************** Static global variables **************************/ - -/** - * Own private key. - */ -static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key; - - -/******************************************************************************/ -/************************ MAIN FUNCTIONS ****************************/ -/******************************************************************************/ - -/** - * Task run during shutdown. - * - * @param cls unused - * @param tc unused - */ -static void -shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutting down\n"); - - shutting_down = GNUNET_YES; - - GML_shutdown (); - GMH_shutdown (); - GMC_shutdown (); - GMT_shutdown (); - GMD_shutdown (); - GMP_shutdown (); - - GNUNET_STATISTICS_destroy (stats, GNUNET_NO); - stats = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shut down\n"); -} - - -/** - * Process cadet requests. - * - * @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) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting to run\n"); - - stats = GNUNET_STATISTICS_create ("cadet", c); - - /* Scheduled the task to clean up when shutdown is called */ - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, - NULL); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "reading key\n"); - my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c); - GNUNET_assert (NULL != my_private_key); - GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_full_id.public_key); - myid = GNUNET_PEER_intern (&my_full_id); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "STARTING SERVICE (CADET) for peer [%s]\n", - GNUNET_i2s (&my_full_id)); - - GML_init (server); /* Local clients */ - GMH_init (c); /* Hellos */ - GMC_init (c); /* Connections */ - GMP_init (c); /* Peers */ - GMD_init (c); /* DHT */ - GMT_init (c, my_private_key); /* Tunnels */ - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cadet service running\n"); -} - - -/** - * The main function for the cadet 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) -{ - int ret; - int r; - - shutting_down = GNUNET_NO; - r = GNUNET_SERVICE_run (argc, argv, "cadet", GNUNET_SERVICE_OPTION_NONE, &run, - NULL); - GNUNET_free (my_private_key); - ret = (GNUNET_OK == r) ? 0 : 1; - - return ret; -} diff --git a/src/mesh/gnunet-service-cadet_channel.c b/src/mesh/gnunet-service-cadet_channel.c deleted file mode 100644 index 91338d5c0..000000000 --- a/src/mesh/gnunet-service-cadet_channel.c +++ /dev/null @@ -1,2432 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2013 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_util_lib.h" - -#include "gnunet_statistics_service.h" - -#include "cadet.h" -#include "cadet_protocol.h" - -#include "gnunet-service-cadet_channel.h" -#include "gnunet-service-cadet_local.h" -#include "gnunet-service-cadet_tunnel.h" -#include "gnunet-service-cadet_peer.h" - -#define LOG(level, ...) GNUNET_log_from(level,"cadet-chn",__VA_ARGS__) - -#define CADET_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(\ - GNUNET_TIME_UNIT_MILLISECONDS, 250) -#define CADET_RETRANSMIT_MARGIN 4 - - -/** - * All the states a connection can be in. - */ -enum CadetChannelState -{ - /** - * Uninitialized status, should never appear in operation. - */ - CADET_CHANNEL_NEW, - - /** - * Connection create message sent, waiting for ACK. - */ - CADET_CHANNEL_SENT, - - /** - * Connection confirmed, ready to carry traffic. - */ - CADET_CHANNEL_READY, -}; - - -/** - * Info holder for channel messages in queues. - */ -struct CadetChannelQueue -{ - /** - * Tunnel Queue. - */ - struct CadetTunnel3Queue *tq; - - /** - * Message type (DATA/DATA_ACK) - */ - uint16_t type; - - /** - * Message copy (for DATAs, to start retransmission timer) - */ - struct CadetReliableMessage *copy; - - /** - * Reliability (for DATA_ACKs, to access rel->ack_q) - */ - struct CadetChannelReliability *rel; -}; - - -/** - * Info needed to retry a message in case it gets lost. - */ -struct CadetReliableMessage -{ - /** - * Double linked list, FIFO style - */ - struct CadetReliableMessage *next; - struct CadetReliableMessage *prev; - - /** - * Type of message (payload, channel management). - */ - int16_t type; - - /** - * Tunnel Reliability queue this message is in. - */ - struct CadetChannelReliability *rel; - - /** - * ID of the message (ACK needed to free) - */ - uint32_t mid; - - /** - * Tunnel Queue. - */ - struct CadetChannelQueue *chq; - - /** - * When was this message issued (to calculate ACK delay) - */ - struct GNUNET_TIME_Absolute timestamp; - - /* struct GNUNET_CADET_Data with payload */ -}; - - -/** - * Info about the traffic state for a client in a channel. - */ -struct CadetChannelReliability -{ - /** - * Channel this is about. - */ - struct CadetChannel *ch; - - /** - * DLL of messages sent and not yet ACK'd. - */ - struct CadetReliableMessage *head_sent; - struct CadetReliableMessage *tail_sent; - - /** - * DLL of messages received out of order. - */ - struct CadetReliableMessage *head_recv; - struct CadetReliableMessage *tail_recv; - - /** - * Messages received. - */ - unsigned int n_recv; - - /** - * Next MID to use for outgoing traffic. - */ - uint32_t mid_send; - - /** - * Next MID expected for incoming traffic. - */ - uint32_t mid_recv; - - /** - * Handle for queued unique data CREATE, DATA_ACK. - */ - struct CadetChannelQueue *uniq; - - /** - * Can we send data to the client? - */ - int client_ready; - - /** - * Can the client send data to us? - */ - int client_allowed; - - /** - * Task to resend/poll in case no ACK is received. - */ - GNUNET_SCHEDULER_TaskIdentifier retry_task; - - /** - * Counter for exponential backoff. - */ - struct GNUNET_TIME_Relative retry_timer; - - /** - * How long does it usually take to get an ACK. - */ - struct GNUNET_TIME_Relative expected_delay; -}; - - -/** - * Struct containing all information regarding a channel to a remote client. - */ -struct CadetChannel -{ - /** - * Tunnel this channel is in. - */ - struct CadetTunnel3 *t; - - /** - * Destination port of the channel. - */ - uint32_t port; - - /** - * Global channel number ( < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) - */ - CADET_ChannelNumber gid; - - /** - * Local tunnel number for root (owner) client. - * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI or 0 ) - */ - CADET_ChannelNumber lid_root; - - /** - * Local tunnel number for local destination clients (incoming number) - * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV or 0). - */ - CADET_ChannelNumber lid_dest; - - /** - * Channel state. - */ - enum CadetChannelState state; - - /** - * Is the tunnel bufferless (minimum latency)? - */ - int nobuffer; - - /** - * Is the tunnel reliable? - */ - int reliable; - - /** - * Last time the channel was used - */ - struct GNUNET_TIME_Absolute timestamp; - - /** - * Client owner of the tunnel, if any - */ - struct CadetClient *root; - - /** - * Client destination of the tunnel, if any. - */ - struct CadetClient *dest; - - /** - * Flag to signal the destruction of the channel. - * If this is set GNUNET_YES the channel will be destroyed - * when the queue is empty. - */ - int destroy; - - /** - * Total (reliable) messages pending ACK for this channel. - */ - unsigned int pending_messages; - - /** - * Reliability data. - * Only present (non-NULL) at the owner of a tunnel. - */ - struct CadetChannelReliability *root_rel; - - /** - * Reliability data. - * Only present (non-NULL) at the destination of a tunnel. - */ - struct CadetChannelReliability *dest_rel; - -}; - - -/******************************************************************************/ -/******************************* GLOBALS ***********************************/ -/******************************************************************************/ - -/** - * Global handle to the statistics service. - */ -extern struct GNUNET_STATISTICS_Handle *stats; - -/** - * Local peer own ID (memory efficient handle). - */ -extern GNUNET_PEER_Id myid; - - -/******************************************************************************/ -/******************************** STATIC ***********************************/ -/******************************************************************************/ - -/** - * Destroy a reliable message after it has been acknowledged, either by - * direct mid ACK or bitfield. Updates the appropriate data structures and - * timers and frees all memory. - * - * @param copy Message that is no longer needed: remote peer got it. - * @param update_time Is the timing information relevant? - * If this message is ACK in a batch the timing information - * is skewed by the retransmission, count only for the - * retransmitted message. - */ -static int -rel_message_free (struct CadetReliableMessage *copy, int update_time); - -/** - * send a channel create message. - * - * @param ch Channel for which to send. - */ -static void -send_create (struct CadetChannel *ch); - -/** - * Confirm we got a channel create, FWD ack. - * - * @param ch The channel to confirm. - * @param fwd Should we send a FWD ACK? (going dest->root) - * @param reaction This ACK is a reaction to a duplicate CREATE, don't save. - */ -static void -send_ack (struct CadetChannel *ch, int fwd, int reaction); - - - -/** - * Test if the channel is loopback: both root and dest are on the local peer. - * - * @param ch Channel to test. - * - * @return #GNUNET_YES if channel is loopback, #GNUNET_NO otherwise. - */ -static int -is_loopback (const struct CadetChannel *ch) -{ - if (NULL != ch->t) - return GMT_is_loopback (ch->t); - - return (NULL != ch->root && NULL != ch->dest); -} - - -/** - * Save a copy of the data message for later retransmission. - * - * @param msg Message to copy. - * @param mid Message ID. - * @param rel Reliability data for retransmission. - */ -static struct CadetReliableMessage * -copy_message (const struct GNUNET_CADET_Data *msg, uint32_t mid, - struct CadetChannelReliability *rel) -{ - struct CadetReliableMessage *copy; - uint16_t size; - - size = ntohs (msg->header.size); - copy = GNUNET_malloc (sizeof (*copy) + size); - copy->mid = mid; - copy->rel = rel; - copy->type = GNUNET_MESSAGE_TYPE_CADET_DATA; - memcpy (©[1], msg, size); - - return copy; -} - -/** - * We have received a message out of order, or the client is not ready. - * Buffer it until we receive an ACK from the client or the missing - * message from the channel. - * - * @param msg Message to buffer (MUST be of type CADET_DATA). - * @param rel Reliability data to the corresponding direction. - */ -static void -add_buffered_data (const struct GNUNET_CADET_Data *msg, - struct CadetChannelReliability *rel) -{ - struct CadetReliableMessage *copy; - struct CadetReliableMessage *prev; - uint32_t mid; - - mid = ntohl (msg->mid); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data %u\n", mid); - - rel->n_recv++; - - // FIXME do something better than O(n), although n < 64... - // FIXME start from the end (most messages are the latest ones) - for (prev = rel->head_recv; NULL != prev; prev = prev->next) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " prev %u\n", prev->mid); - if (prev->mid == mid) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " already there!\n"); - return; - } - else if (GM_is_pid_bigger (prev->mid, mid)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " bingo!\n"); - copy = copy_message (msg, mid, rel); - GNUNET_CONTAINER_DLL_insert_before (rel->head_recv, rel->tail_recv, - prev, copy); - return; - } - } - copy = copy_message (msg, mid, rel); - LOG (GNUNET_ERROR_TYPE_DEBUG, " insert at tail!\n"); - GNUNET_CONTAINER_DLL_insert_tail (rel->head_recv, rel->tail_recv, copy); - LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data END\n"); -} - - -/** - * Add a destination client to a channel, initializing all data structures - * in the channel and the client. - * - * @param ch Channel to which add the destination. - * @param c Client which to add to the channel. - */ -static void -add_destination (struct CadetChannel *ch, struct CadetClient *c) -{ - if (NULL != ch->dest) - { - GNUNET_break (0); - return; - } - - /* Assign local id as destination */ - ch->lid_dest = GML_get_next_chid (c); - - /* Store in client's hashmap */ - GML_channel_add (c, ch->lid_dest, ch); - - GNUNET_break (NULL == ch->dest_rel); - ch->dest_rel = GNUNET_new (struct CadetChannelReliability); - ch->dest_rel->ch = ch; - ch->dest_rel->expected_delay.rel_value_us = 0; - ch->dest_rel->retry_timer = CADET_RETRANSMIT_TIME; - - ch->dest = c; -} - - -/** - * Set options in a channel, extracted from a bit flag field. - * - * @param ch Channel to set options to. - * @param options Bit array in host byte order. - */ -static void -channel_set_options (struct CadetChannel *ch, uint32_t options) -{ - ch->nobuffer = (options & GNUNET_CADET_OPTION_NOBUFFER) != 0 ? - GNUNET_YES : GNUNET_NO; - ch->reliable = (options & GNUNET_CADET_OPTION_RELIABLE) != 0 ? - GNUNET_YES : GNUNET_NO; -} - - -/** - * Get a bit flag field with the options of a channel. - * - * @param ch Channel to get options from. - * - * @return Bit array in host byte order. - */ -static uint32_t -channel_get_options (struct CadetChannel *ch) -{ - uint32_t options; - - options = 0; - if (ch->nobuffer) - options |= GNUNET_CADET_OPTION_NOBUFFER; - if (ch->reliable) - options |= GNUNET_CADET_OPTION_RELIABLE; - - return options; -} - - -/** - * Notify a client that the channel is no longer valid. - * - * @param ch Channel that is destroyed. - * @param local_only Should we avoid sending it to other peers? - */ -static void -send_destroy (struct CadetChannel *ch, int local_only) -{ - struct GNUNET_CADET_ChannelManage msg; - - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY); - msg.header.size = htons (sizeof (msg)); - msg.chid = htonl (ch->gid); - - /* If root is not NULL, notify. - * If it's NULL, check lid_root. When a local destroy comes in, root - * is set to NULL but lid_root is left untouched. In this case, do nothing, - * the client is the one who requested the channel to be destroyed. - */ - if (NULL != ch->root) - GML_send_channel_destroy (ch->root, ch->lid_root); - else if (0 == ch->lid_root && GNUNET_NO == local_only) - GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO, NULL); - - if (NULL != ch->dest) - GML_send_channel_destroy (ch->dest, ch->lid_dest); - else if (0 == ch->lid_dest && GNUNET_NO == local_only) - GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_YES, NULL); -} - - -/** - * Notify the destination client that a new incoming channel was created. - * - * @param ch Channel that was created. - */ -static void -send_client_create (struct CadetChannel *ch) -{ - uint32_t opt; - - if (NULL == ch->dest) - return; - - opt = 0; - opt |= GNUNET_YES == ch->reliable ? GNUNET_CADET_OPTION_RELIABLE : 0; - opt |= GNUNET_YES == ch->nobuffer ? GNUNET_CADET_OPTION_NOBUFFER : 0; - GML_send_channel_create (ch->dest, ch->lid_dest, ch->port, opt, - GMT_get_destination (ch->t)); - -} - - -/** - * Send data to a client. - * - * If the client is ready, send directly, otherwise buffer while listening - * for a local ACK. - * - * @param ch Channel - * @param msg Message. - * @param fwd Is this a fwd (root->dest) message? - */ -static void -send_client_data (struct CadetChannel *ch, - const struct GNUNET_CADET_Data *msg, - int fwd) -{ - if (fwd) - { - if (ch->dest_rel->client_ready) - GML_send_data (ch->dest, msg, ch->lid_dest); - else - add_buffered_data (msg, ch->dest_rel); - } - else - { - if (ch->root_rel->client_ready) - GML_send_data (ch->root, msg, ch->lid_root); - else - add_buffered_data (msg, ch->root_rel); - } -} - - -/** - * Send a buffered message to the client, for in order delivery or - * as result of client ACK. - * - * @param ch Channel on which to empty the message buffer. - * @param c Client to send to. - * @param fwd Is this to send FWD data?. - */ -static void -send_client_buffered_data (struct CadetChannel *ch, - struct CadetClient *c, - int fwd) -{ - struct CadetReliableMessage *copy; - struct CadetChannelReliability *rel; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data\n"); - rel = fwd ? ch->dest_rel : ch->root_rel; - if (GNUNET_NO == rel->client_ready) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "client not ready\n"); - return; - } - - copy = rel->head_recv; - /* We never buffer channel management messages */ - if (NULL != copy) - { - if (copy->mid == rel->mid_recv || GNUNET_NO == ch->reliable) - { - struct GNUNET_CADET_Data *msg = (struct GNUNET_CADET_Data *) ©[1]; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - " have %u! now expecting %u\n", - copy->mid, rel->mid_recv + 1); - send_client_data (ch, msg, fwd); - rel->n_recv--; - rel->mid_recv++; - GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy); - LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE RECV %p\n", copy); - GNUNET_free (copy); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - " reliable && don't have %u, next is %u\n", - rel->mid_recv, - copy->mid); - if (GNUNET_YES == ch->destroy) - { - /* We don't have the next data piece and the remote peer has closed the - * channel. We won't receive it anymore, so just destroy the channel. - * FIXME: wait some time to allow other connections to - * deliver missing messages - */ - send_destroy (ch, GNUNET_YES); - GMCH_destroy (ch); - } - } - } - LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data END\n"); -} - - -/** - * Allow a client to send more data. - * - * In case the client was already allowed to send data, do nothing. - * - * @param ch Channel. - * @param fwd Is this a FWD ACK? (FWD ACKs are sent to root) - */ -static void -send_client_ack (struct CadetChannel *ch, int fwd) -{ - struct CadetChannelReliability *rel = fwd ? ch->root_rel : ch->dest_rel; - struct CadetClient *c = fwd ? ch->root : ch->dest; - - if (NULL == c) - { - GNUNET_break (GNUNET_NO != ch->destroy); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, - " sending %s ack to client on channel %s\n", - GM_f2s (fwd), GMCH_2s (ch)); - - if (NULL == rel) - { - GNUNET_break (0); - return; - } - - if (GNUNET_YES == rel->client_allowed) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " already allowed\n"); - return; - } - rel->client_allowed = GNUNET_YES; - - GML_send_ack (c, fwd ? ch->lid_root : ch->lid_dest); -} - - -/** - * Notify the root that the destination rejected the channel. - * - * @param ch Rejected channel. - */ -static void -send_client_nack (struct CadetChannel *ch) -{ - if (NULL == ch->root) - { - GNUNET_break (0); - return; - } - GML_send_channel_nack (ch->root, ch->lid_root); -} - - -/** - * We haven't received an ACK after a certain time: restransmit the message. - * - * @param cls Closure (CadetChannelReliability with the message to restransmit) - * @param tc TaskContext. - */ -static void -channel_retransmit_message (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct CadetChannelReliability *rel = cls; - struct CadetReliableMessage *copy; - struct CadetChannel *ch; - struct GNUNET_CADET_Data *payload; - int fwd; - - rel->retry_task = GNUNET_SCHEDULER_NO_TASK; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; - - ch = rel->ch; - copy = rel->head_sent; - if (NULL == copy) - { - GNUNET_break (0); - return; - } - - payload = (struct GNUNET_CADET_Data *) ©[1]; - fwd = (rel == ch->root_rel); - - /* Message not found in the queue that we are going to use. */ - LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! RETRANSMIT %u\n", copy->mid); - - GMCH_send_prebuilt_message (&payload->header, ch, fwd, copy); - GNUNET_STATISTICS_update (stats, "# data retransmitted", 1, GNUNET_NO); -} - - -/** - * We haven't received an Channel ACK after a certain time: resend the CREATE. - * - * @param cls Closure (CadetChannelReliability of the channel to recreate) - * @param tc TaskContext. - */ -static void -channel_recreate (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct CadetChannelReliability *rel = cls; - - rel->retry_task = GNUNET_SCHEDULER_NO_TASK; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! RE-CREATE\n"); - GNUNET_STATISTICS_update (stats, "# data retransmitted", 1, GNUNET_NO); - - if (rel == rel->ch->root_rel) - { - send_create (rel->ch); - } - else if (rel == rel->ch->dest_rel) - { - send_ack (rel->ch, GNUNET_YES, GNUNET_NO); - } - else - { - GNUNET_break (0); - } - -} - - -/** - * Message has been sent: start retransmission timer. - * - * @param cls Closure (queue structure). - * @param t Tunnel. - * @param q Queue handler (no longer valid). - * @param type Type of message. - * @param size Size of the message. - */ -static void -ch_message_sent (void *cls, - struct CadetTunnel3 *t, - struct CadetTunnel3Queue *q, - uint16_t type, size_t size) -{ - struct CadetChannelQueue *chq = cls; - struct CadetReliableMessage *copy = chq->copy; - struct CadetChannelReliability *rel; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "channel message sent callback %s\n", - GM_m2s (chq->type)); - - switch (chq->type) - { - case GNUNET_MESSAGE_TYPE_CADET_DATA: - LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SENT DATA MID %u\n", copy->mid); - GNUNET_assert (chq == copy->chq); - copy->timestamp = GNUNET_TIME_absolute_get (); - rel = copy->rel; - if (GNUNET_SCHEDULER_NO_TASK == rel->retry_task) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "!! scheduling retry in 4 * %s\n", - GNUNET_STRINGS_relative_time_to_string (rel->expected_delay, - GNUNET_YES)); - if (0 != rel->expected_delay.rel_value_us) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "!! delay != 0\n"); - rel->retry_timer = - GNUNET_TIME_relative_multiply (rel->expected_delay, - CADET_RETRANSMIT_MARGIN); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "!! delay reset\n"); - rel->retry_timer = CADET_RETRANSMIT_TIME; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, "!! using delay %s\n", - GNUNET_STRINGS_relative_time_to_string (rel->retry_timer, - GNUNET_NO)); - rel->retry_task = - GNUNET_SCHEDULER_add_delayed (rel->retry_timer, - &channel_retransmit_message, rel); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "!! retry task %u\n", rel->retry_task); - } - copy->chq = NULL; - break; - - - case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK: - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE: - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK: - LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SENT %s\n", GM_m2s (chq->type)); - rel = chq->rel; - GNUNET_assert (rel->uniq == chq); - rel->uniq = NULL; - - if (CADET_CHANNEL_READY != rel->ch->state - && GNUNET_MESSAGE_TYPE_CADET_DATA_ACK != type - && GNUNET_NO == rel->ch->destroy) - { - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == rel->retry_task); - LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! STD BACKOFF %s\n", - GNUNET_STRINGS_relative_time_to_string (rel->retry_timer, - GNUNET_NO)); - rel->retry_timer = GNUNET_TIME_STD_BACKOFF (rel->retry_timer); - rel->retry_task = GNUNET_SCHEDULER_add_delayed (rel->retry_timer, - &channel_recreate, rel); - } - break; - - default: - GNUNET_break (0); - } - - GNUNET_free (chq); -} - - -/** - * send a channel create message. - * - * @param ch Channel for which to send. - */ -static void -send_create (struct CadetChannel *ch) -{ - struct GNUNET_CADET_ChannelCreate msgcc; - - msgcc.header.size = htons (sizeof (msgcc)); - msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE); - msgcc.chid = htonl (ch->gid); - msgcc.port = htonl (ch->port); - msgcc.opt = htonl (channel_get_options (ch)); - - GMCH_send_prebuilt_message (&msgcc.header, ch, GNUNET_YES, NULL); -} - - -/** - * Confirm we got a channel create or FWD ack. - * - * @param ch The channel to confirm. - * @param fwd Should we send a FWD ACK? (going dest->root) - * @param reaction This ACK is a reaction to a duplicate CREATE, don't save. - */ -static void -send_ack (struct CadetChannel *ch, int fwd, int reaction) -{ - struct GNUNET_CADET_ChannelManage msg; - - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK); - LOG (GNUNET_ERROR_TYPE_DEBUG, " sending channel %s ack for channel %s\n", - GM_f2s (fwd), GMCH_2s (ch)); - - msg.chid = htonl (ch->gid); - GMCH_send_prebuilt_message (&msg.header, ch, !fwd, reaction ? &msg : NULL); -} - - -/** - * Send a message and don't keep any info about it: we won't need to cancel it - * or resend it. - * - * @param msg Header of the message to fire away. - * @param ch Channel on which the message should go. - * @param force Is this a forced (undroppable) message? - */ -static void -fire_and_forget (const struct GNUNET_MessageHeader *msg, - struct CadetChannel *ch, - int force) -{ - GNUNET_break (NULL == GMT_send_prebuilt_message (msg, ch->t, NULL, - force, NULL, NULL)); -} - - -/** - * Notify that a channel create didn't succeed. - * - * @param ch The channel to reject. - */ -static void -send_nack (struct CadetChannel *ch) -{ - struct GNUNET_CADET_ChannelManage msg; - - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK); - LOG (GNUNET_ERROR_TYPE_DEBUG, - " sending channel NACK for channel %s\n", - GMCH_2s (ch)); - - msg.chid = htonl (ch->gid); - GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO, NULL); -} - - -/** - * Destroy all reliable messages queued for a channel, - * during a channel destruction. - * Frees the reliability structure itself. - * - * @param rel Reliability data for a channel. - */ -static void -channel_rel_free_all (struct CadetChannelReliability *rel) -{ - struct CadetReliableMessage *copy; - struct CadetReliableMessage *next; - - if (NULL == rel) - return; - - for (copy = rel->head_recv; NULL != copy; copy = next) - { - next = copy->next; - GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy); - LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE BATCH RECV %p\n", copy); - GNUNET_break (NULL == copy->chq); - GNUNET_free (copy); - } - for (copy = rel->head_sent; NULL != copy; copy = next) - { - next = copy->next; - GNUNET_CONTAINER_DLL_remove (rel->head_sent, rel->tail_sent, copy); - LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE BATCH %p\n", copy); - if (NULL != copy->chq) - { - if (NULL != copy->chq->tq) - { - GMT_cancel (copy->chq->tq); - /* ch_message_sent will free copy->q */ - } - else - { - GNUNET_free (copy->chq); - GNUNET_break (0); - } - } - GNUNET_free (copy); - } - if (NULL != rel->uniq && NULL != rel->uniq->tq) - { - GMT_cancel (rel->uniq->tq); - /* ch_message_sent is called freeing uniq */ - } - if (GNUNET_SCHEDULER_NO_TASK != rel->retry_task) - { - GNUNET_SCHEDULER_cancel (rel->retry_task); - rel->retry_task = GNUNET_SCHEDULER_NO_TASK; - } - GNUNET_free (rel); -} - - -/** - * Mark future messages as ACK'd. - * - * @param rel Reliability data. - * @param msg DataACK message with a bitfield of future ACK'd messages. - */ -static void -channel_rel_free_sent (struct CadetChannelReliability *rel, - const struct GNUNET_CADET_DataACK *msg) -{ - struct CadetReliableMessage *copy; - struct CadetReliableMessage *next; - uint64_t bitfield; - uint64_t mask; - uint32_t mid; - uint32_t target; - unsigned int i; - - bitfield = msg->futures; - mid = ntohl (msg->mid); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "!!! free_sent_reliable %u %llX\n", - mid, bitfield); - LOG (GNUNET_ERROR_TYPE_DEBUG, - " rel %p, head %p\n", - rel, rel->head_sent); - for (i = 0, copy = rel->head_sent; - i < 64 && NULL != copy && 0 != bitfield; - i++) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - " trying bit %u (mid %u)\n", - i, mid + i + 1); - mask = 0x1LL << i; - if (0 == (bitfield & mask)) - continue; - - LOG (GNUNET_ERROR_TYPE_DEBUG, " set!\n"); - /* Bit was set, clear the bit from the bitfield */ - bitfield &= ~mask; - - /* The i-th bit was set. Do we have that copy? */ - /* Skip copies with mid < target */ - target = mid + i + 1; - LOG (GNUNET_ERROR_TYPE_DEBUG, " target %u\n", target); - while (NULL != copy && GM_is_pid_bigger (target, copy->mid)) - copy = copy->next; - - /* Did we run out of copies? (previously freed, it's ok) */ - if (NULL == copy) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "run out of copies...\n"); - return; - } - - /* Did we overshoot the target? (previously freed, it's ok) */ - if (GM_is_pid_bigger (copy->mid, target)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " next copy %u\n", copy->mid); - continue; - } - - /* Now copy->mid == target, free it */ - next = copy->next; - GNUNET_break (GNUNET_YES != rel_message_free (copy, GNUNET_YES)); - copy = next; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, "free_sent_reliable END\n"); -} - - -/** - * Destroy a reliable message after it has been acknowledged, either by - * direct mid ACK or bitfield. Updates the appropriate data structures and - * timers and frees all memory. - * - * @param copy Message that is no longer needed: remote peer got it. - * @param update_time Is the timing information relevant? - * If this message is ACK in a batch the timing information - * is skewed by the retransmission, count only for the - * retransmitted message. - * - * @return #GNUNET_YES if channel was destroyed as a result of the call, - * #GNUNET_NO otherwise. - */ -static int -rel_message_free (struct CadetReliableMessage *copy, int update_time) -{ - struct CadetChannelReliability *rel; - struct GNUNET_TIME_Relative time; - - rel = copy->rel; - LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Freeing %u\n", copy->mid); - if (update_time) - { - time = GNUNET_TIME_absolute_get_duration (copy->timestamp); - if (0 == rel->expected_delay.rel_value_us) - rel->expected_delay = time; - else - { - rel->expected_delay.rel_value_us *= 7; - rel->expected_delay.rel_value_us += time.rel_value_us; - rel->expected_delay.rel_value_us /= 8; - } - LOG (GNUNET_ERROR_TYPE_INFO, "!!! took %s, new delay %s\n", - GNUNET_STRINGS_relative_time_to_string (time, GNUNET_NO), - GNUNET_STRINGS_relative_time_to_string (rel->expected_delay, - GNUNET_NO)); - rel->retry_timer = rel->expected_delay; - } - else - { - LOG (GNUNET_ERROR_TYPE_INFO, "!!! batch free, ignoring timing\n"); - } - rel->ch->pending_messages--; - if (NULL != copy->chq) - { - GMT_cancel (copy->chq->tq); - /* copy->q is set to NULL by ch_message_sent */ - } - GNUNET_CONTAINER_DLL_remove (rel->head_sent, rel->tail_sent, copy); - LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE %p\n", copy); - GNUNET_free (copy); - - if (GNUNET_NO != rel->ch->destroy && 0 == rel->ch->pending_messages) - { - GMCH_destroy (rel->ch); - return GNUNET_YES; - } - return GNUNET_NO; -} - - -/** - * Channel was ACK'd by remote peer, mark as ready and cancel retransmission. - * - * @param ch Channel to mark as ready. - * @param fwd Was the ACK message a FWD ACK? (dest->root, SYNACK) - */ -static void -channel_confirm (struct CadetChannel *ch, int fwd) -{ - struct CadetChannelReliability *rel; - enum CadetChannelState oldstate; - - rel = fwd ? ch->root_rel : ch->dest_rel; - if (NULL == rel) - { - GNUNET_break (GNUNET_NO != ch->destroy); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " channel confirm %s %s\n", - GM_f2s (fwd), GMCH_2s (ch)); - oldstate = ch->state; - ch->state = CADET_CHANNEL_READY; - - if (CADET_CHANNEL_READY != oldstate || GNUNET_YES == is_loopback (ch)) - { - rel->client_ready = GNUNET_YES; - rel->expected_delay = rel->retry_timer; - LOG (GNUNET_ERROR_TYPE_DEBUG, " !! retry timer confirm %s\n", - GNUNET_STRINGS_relative_time_to_string (rel->retry_timer, GNUNET_NO)); - if (GMT_get_connections_buffer (ch->t) > 0 || GMT_is_loopback (ch->t)) - send_client_ack (ch, fwd); - - if (GNUNET_SCHEDULER_NO_TASK != rel->retry_task) - { - GNUNET_SCHEDULER_cancel (rel->retry_task); - rel->retry_task = GNUNET_SCHEDULER_NO_TASK; - } - else if (NULL != rel->uniq) - { - GMT_cancel (rel->uniq->tq); - /* ch_message_sent will free and NULL uniq */ - } - else - { - if (GNUNET_NO == is_loopback (ch)) - { - /* We SHOULD have been trying to retransmit this! */ - GNUNET_break (0); - } - } - } - - /* In case of a FWD ACK (SYNACK) send a BCK ACK (ACK). */ - if (GNUNET_YES == fwd) - send_ack (ch, GNUNET_NO, GNUNET_NO); -} - - -/** - * Save a copy to retransmit in case it gets lost. - * - * Initializes all needed callbacks and timers. - * - * @param ch Channel this message goes on. - * @param msg Message to copy. - * @param fwd Is this fwd traffic? - */ -static struct CadetReliableMessage * -channel_save_copy (struct CadetChannel *ch, - const struct GNUNET_MessageHeader *msg, - int fwd) -{ - struct CadetChannelReliability *rel; - struct CadetReliableMessage *copy; - uint32_t mid; - uint16_t type; - uint16_t size; - - rel = fwd ? ch->root_rel : ch->dest_rel; - mid = rel->mid_send - 1; - type = ntohs (msg->type); - size = ntohs (msg->size); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SAVE %u %s\n", mid, GM_m2s (type)); - copy = GNUNET_malloc (sizeof (struct CadetReliableMessage) + size); - LOG (GNUNET_ERROR_TYPE_DEBUG, " at %p\n", copy); - copy->mid = mid; - copy->rel = rel; - copy->type = type; - memcpy (©[1], msg, size); - GNUNET_CONTAINER_DLL_insert_tail (rel->head_sent, rel->tail_sent, copy); - ch->pending_messages++; - - return copy; -} - - -/** - * Create a new channel. - * - * @param t Tunnel this channel is in. - * @param owner Client that owns the channel, NULL for foreign channels. - * @param lid_root Local ID for root client. - * - * @return A new initialized channel. NULL on error. - */ -static struct CadetChannel * -channel_new (struct CadetTunnel3 *t, - struct CadetClient *owner, - CADET_ChannelNumber lid_root) -{ - struct CadetChannel *ch; - - ch = GNUNET_new (struct CadetChannel); - ch->root = owner; - ch->lid_root = lid_root; - ch->t = t; - - GNUNET_STATISTICS_update (stats, "# channels", 1, GNUNET_NO); - - if (NULL != owner) - { - ch->gid = GMT_get_next_chid (t); - GML_channel_add (owner, lid_root, ch); - } - GMT_add_channel (t, ch); - - return ch; -} - - -/** - * Handle a loopback message: call the appropriate handler for the message type. - * - * @param ch Channel this message is on. - * @param msgh Message header. - * @param fwd Is this FWD traffic? - */ -void -handle_loopback (struct CadetChannel *ch, - const struct GNUNET_MessageHeader *msgh, - int fwd) -{ - uint16_t type; - - type = ntohs (msgh->type); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Loopback %s %s message!\n", - GM_f2s (fwd), GM_m2s (type)); - - switch (type) - { - case GNUNET_MESSAGE_TYPE_CADET_DATA: - /* Don't send hop ACK, wait for client to ACK */ - LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SEND loopback %u (%u)\n", - ntohl (((struct GNUNET_CADET_Data *) msgh)->mid), ntohs (msgh->size)); - GMCH_handle_data (ch, (struct GNUNET_CADET_Data *) msgh, fwd); - break; - - case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK: - GMCH_handle_data_ack (ch, (struct GNUNET_CADET_DataACK *) msgh, fwd); - break; - - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE: - GMCH_handle_create (ch->t, - (struct GNUNET_CADET_ChannelCreate *) msgh); - break; - - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK: - GMCH_handle_ack (ch, - (struct GNUNET_CADET_ChannelManage *) msgh, - fwd); - break; - - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK: - GMCH_handle_nack (ch); - break; - - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: - GMCH_handle_destroy (ch, - (struct GNUNET_CADET_ChannelManage *) msgh, - fwd); - break; - - default: - GNUNET_break_op (0); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "end-to-end message not known (%u)\n", - ntohs (msgh->type)); - } -} - - - -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ - -/** - * Destroy a channel and free all resources. - * - * @param ch Channel to destroy. - */ -void -GMCH_destroy (struct CadetChannel *ch) -{ - struct CadetClient *c; - struct CadetTunnel3 *t; - - if (NULL == ch) - return; - if (2 == ch->destroy) - return; /* recursive call */ - ch->destroy = 2; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying channel %s:%u\n", - GMT_2s (ch->t), ch->gid); - GMCH_debug (ch); - - c = ch->root; - if (NULL != c) - { - GML_channel_remove (c, ch->lid_root, ch); - } - - c = ch->dest; - if (NULL != c) - { - GML_channel_remove (c, ch->lid_dest, ch); - } - - channel_rel_free_all (ch->root_rel); - channel_rel_free_all (ch->dest_rel); - - t = ch->t; - GMT_remove_channel (t, ch); - GNUNET_STATISTICS_update (stats, "# channels", -1, GNUNET_NO); - - GNUNET_free (ch); - GMT_destroy_if_empty (t); -} - - -/** - * Get the channel's public ID. - * - * @param ch Channel. - * - * @return ID used to identify the channel with the remote peer. - */ -CADET_ChannelNumber -GMCH_get_id (const struct CadetChannel *ch) -{ - return ch->gid; -} - - -/** - * Get the channel tunnel. - * - * @param ch Channel to get the tunnel from. - * - * @return tunnel of the channel. - */ -struct CadetTunnel3 * -GMCH_get_tunnel (const struct CadetChannel *ch) -{ - return ch->t; -} - - -/** - * Get free buffer space towards the client on a specific channel. - * - * @param ch Channel. - * @param fwd Is query about FWD traffic? - * - * @return Free buffer space [0 - 64] - */ -unsigned int -GMCH_get_buffer (struct CadetChannel *ch, int fwd) -{ - struct CadetChannelReliability *rel; - - rel = fwd ? ch->dest_rel : ch->root_rel; - - /* If rel is NULL it means that the end is not yet created, - * most probably is a loopback channel at the point of sending - * the ChannelCreate to itself. - */ - if (NULL == rel) - return 64; - - return (64 - rel->n_recv); -} - - -/** - * Get flow control status of end point: is client allow to send? - * - * @param ch Channel. - * @param fwd Is query about FWD traffic? (Request root status). - * - * @return #GNUNET_YES if client is allowed to send us data. - */ -int -GMCH_get_allowed (struct CadetChannel *ch, int fwd) -{ - struct CadetChannelReliability *rel; - - rel = fwd ? ch->root_rel : ch->dest_rel; - - if (NULL == rel) - { - /* Probably shutting down: root/dest NULL'ed to mark disconnection */ - GNUNET_break (GNUNET_NO != ch->destroy); - return 0; - } - - return rel->client_allowed; -} - - -/** - * Is the root client for this channel on this peer? - * - * @param ch Channel. - * @param fwd Is this for fwd traffic? - * - * @return #GNUNET_YES in case it is. - */ -int -GMCH_is_origin (struct CadetChannel *ch, int fwd) -{ - struct CadetClient *c; - - c = fwd ? ch->root : ch->dest; - return NULL != c; -} - - -/** - * Is the destination client for this channel on this peer? - * - * @param ch Channel. - * @param fwd Is this for fwd traffic? - * - * @return #GNUNET_YES in case it is. - */ -int -GMCH_is_terminal (struct CadetChannel *ch, int fwd) -{ - struct CadetClient *c; - - c = fwd ? ch->dest : ch->root; - return NULL != c; -} - - -/** - * Send an end-to-end ACK message for the most recent in-sequence payload. - * - * If channel is not reliable, do nothing. - * - * @param ch Channel this is about. - * @param fwd Is for FWD traffic? (ACK dest->owner) - */ -void -GMCH_send_data_ack (struct CadetChannel *ch, int fwd) -{ - struct GNUNET_CADET_DataACK msg; - struct CadetChannelReliability *rel; - struct CadetReliableMessage *copy; - unsigned int delta; - uint64_t mask; - uint32_t ack; - - if (GNUNET_NO == ch->reliable) - { - return; - } - rel = fwd ? ch->dest_rel : ch->root_rel; - ack = rel->mid_recv - 1; - LOG (GNUNET_ERROR_TYPE_INFO, "===> DATA_ACK for %u\n", ack); - - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_DATA_ACK); - msg.header.size = htons (sizeof (msg)); - msg.chid = htonl (ch->gid); - msg.futures = 0; - for (copy = rel->head_recv; NULL != copy; copy = copy->next) - { - if (copy->type != GNUNET_MESSAGE_TYPE_CADET_DATA) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "!! Type %s, expected DATA\n", - GM_m2s (copy->type)); - continue; - } - if (copy->mid == ack + 1) - { - ack++; - continue; - } - delta = copy->mid - (ack + 1); - if (63 < delta) - break; - mask = 0x1LL << delta; - msg.futures |= mask; - LOG (GNUNET_ERROR_TYPE_DEBUG, - " !! setting bit for %u (delta %u) (%llX) -> %llX\n", - copy->mid, delta, mask, msg.futures); - } - msg.mid = htonl (ack); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "!!! ACK for %u, futures %llX\n", - ack, msg.futures); - - GMCH_send_prebuilt_message (&msg.header, ch, !fwd, NULL); - LOG (GNUNET_ERROR_TYPE_DEBUG, "send_data_ack END\n"); -} - - -/** - * Allow a client to send us more data, in case it was choked. - * - * @param ch Channel. - * @param fwd Is this about FWD traffic? (Root client). - */ -void -GMCH_allow_client (struct CadetChannel *ch, int fwd) -{ - struct CadetChannelReliability *rel; - unsigned int buffer; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "GMCH allow\n"); - - if (CADET_CHANNEL_READY != ch->state) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " channel not ready yet!\n"); - return; - } - - if (GNUNET_YES == ch->reliable) - { - rel = fwd ? ch->root_rel : ch->dest_rel; - if (NULL == rel) - { - GNUNET_break (GNUNET_NO != ch->destroy); - return; - } - if (NULL != rel->head_sent) - { - if (64 <= rel->mid_send - rel->head_sent->mid) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " too big MID gap! Wait for ACK.\n"); - return; - } - else - LOG (GNUNET_ERROR_TYPE_DEBUG, " gap ok: %u - %u\n", - rel->head_sent->mid, rel->mid_send); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " head sent is NULL\n"); - } - } - - if (is_loopback (ch)) - buffer = GMCH_get_buffer (ch, fwd); - else - buffer = GMT_get_connections_buffer (ch->t); - - if (0 == buffer) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " no buffer space.\n"); - return; - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space %u, allowing\n", buffer); - send_client_ack (ch, fwd); -} - - -/** - * Log channel info. - * - * @param ch Channel. - */ -void -GMCH_debug (struct CadetChannel *ch) -{ - if (NULL == ch) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "*** DEBUG NULL CHANNEL ***\n"); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %s:%X (%p)\n", - GMT_2s (ch->t), ch->gid, ch); - LOG (GNUNET_ERROR_TYPE_DEBUG, " root %p/%p\n", - ch->root, ch->root_rel); - if (NULL != ch->root) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " cli %s\n", GML_2s (ch->root)); - LOG (GNUNET_ERROR_TYPE_DEBUG, " ready %s\n", - ch->root_rel->client_ready ? "YES" : "NO"); - LOG (GNUNET_ERROR_TYPE_DEBUG, " id %X\n", ch->lid_root); - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " dest %p/%p\n", - ch->dest, ch->dest_rel); - if (NULL != ch->dest) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " cli %s\n", GML_2s (ch->dest)); - LOG (GNUNET_ERROR_TYPE_DEBUG, " ready %s\n", - ch->dest_rel->client_ready ? "YES" : "NO"); - LOG (GNUNET_ERROR_TYPE_DEBUG, " id %X\n", ch->lid_dest); - } -} - - -/** - * Handle an ACK given by a client. - * - * Mark client as ready and send him any buffered data we could have for him. - * - * @param ch Channel. - * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by dest and go BCK) - */ -void -GMCH_handle_local_ack (struct CadetChannel *ch, int fwd) -{ - struct CadetChannelReliability *rel; - struct CadetClient *c; - - rel = fwd ? ch->dest_rel : ch->root_rel; - c = fwd ? ch->dest : ch->root; - - rel->client_ready = GNUNET_YES; - send_client_buffered_data (ch, c, fwd); - - if (GNUNET_YES == ch->destroy && 0 == rel->n_recv) - { - send_destroy (ch, GNUNET_YES); - GMCH_destroy (ch); - } - /* if loopback is marked for destruction, no need to ACK to the other peer, - * it requested the destruction and is already gone, therefore, else if. - */ - else if (is_loopback (ch)) - { - unsigned int buffer; - - buffer = GMCH_get_buffer (ch, fwd); - if (0 < buffer) - GMCH_allow_client (ch, fwd); - - return; - } - GMT_send_connection_acks (ch->t); -} - - -/** - * Handle data given by a client. - * - * Check whether the client is allowed to send in this tunnel, save if channel - * is reliable and send an ACK to the client if there is still buffer space - * in the tunnel. - * - * @param ch Channel. - * @param c Client which sent the data. - * @param message Message. - * @param fwd Is this a FWD data? - * - * @return GNUNET_OK if everything goes well, GNUNET_SYSERR in case of en error. - */ -int -GMCH_handle_local_data (struct CadetChannel *ch, - struct CadetClient *c, - struct GNUNET_MessageHeader *message, - int fwd) -{ - struct CadetChannelReliability *rel; - struct GNUNET_CADET_Data *payload; - size_t size = ntohs (message->size); - uint16_t p2p_size = sizeof(struct GNUNET_CADET_Data) + size; - unsigned char cbuf[p2p_size]; - - /* Is the client in the channel? */ - if ( !( (fwd && - ch->root == c) - || - (!fwd && - ch->dest == c) ) ) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - rel = fwd ? ch->root_rel : ch->dest_rel; - - if (GNUNET_NO == rel->client_allowed) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - rel->client_allowed = GNUNET_NO; - - /* Ok, everything is correct, send the message. */ - payload = (struct GNUNET_CADET_Data *) cbuf; - payload->mid = htonl (rel->mid_send); - rel->mid_send++; - memcpy (&payload[1], message, size); - payload->header.size = htons (p2p_size); - payload->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_DATA); - payload->chid = htonl (ch->gid); - LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channel...\n"); - GMCH_send_prebuilt_message (&payload->header, ch, fwd, NULL); - - if (is_loopback (ch)) - { - if (GMCH_get_buffer (ch, fwd) > 0) - GMCH_allow_client (ch, fwd); - - return GNUNET_OK; - } - - if (GMT_get_connections_buffer (ch->t) > 0) - { - GMCH_allow_client (ch, fwd); - } - - return GNUNET_OK; -} - - -/** - * Handle a channel destroy requested by a client. - * - * Destroy the channel and the tunnel in case this was the last channel. - * - * @param ch Channel. - * @param c Client that requested the destruction (to avoid notifying him). - * @param is_root Is the request coming from root? - */ -void -GMCH_handle_local_destroy (struct CadetChannel *ch, - struct CadetClient *c, - int is_root) -{ - ch->destroy = GNUNET_YES; - /* Cleanup after the tunnel */ - if (GNUNET_NO == is_root && c == ch->dest) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is destination.\n", GML_2s (c)); - GML_client_delete_channel (c, ch, ch->lid_dest); - ch->dest = NULL; - } - if (GNUNET_YES == is_root && c == ch->root) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is owner.\n", GML_2s (c)); - GML_client_delete_channel (c, ch, ch->lid_root); - ch->root = NULL; - } - - send_destroy (ch, GNUNET_NO); - if (0 == ch->pending_messages) - GMCH_destroy (ch); -} - - -/** - * Handle a channel create requested by a client. - * - * Create the channel and the tunnel in case this was the first0 channel. - * - * @param c Client that requested the creation (will be the root). - * @param msg Create Channel message. - * - * @return GNUNET_OK if everything went fine, GNUNET_SYSERR otherwise. - */ -int -GMCH_handle_local_create (struct CadetClient *c, - struct GNUNET_CADET_ChannelMessage *msg) -{ - struct CadetChannel *ch; - struct CadetTunnel3 *t; - struct CadetPeer *peer; - CADET_ChannelNumber chid; - - LOG (GNUNET_ERROR_TYPE_DEBUG, " towards %s:%u\n", - GNUNET_i2s (&msg->peer), ntohl (msg->port)); - chid = ntohl (msg->channel_id); - - /* Sanity check for duplicate channel IDs */ - if (NULL != GML_channel_get (c, chid)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - peer = GMP_get (&msg->peer); - GMP_add_tunnel (peer); - t = GMP_get_tunnel (peer); - - if (GMP_get_short_id (peer) == myid) - { - GMT_change_cstate (t, CADET_TUNNEL3_READY); - } - else - { - /* FIXME change to a tunnel API, eliminate ch <-> peer connection */ - GMP_connect (peer); - } - - /* Create channel */ - ch = channel_new (t, c, chid); - if (NULL == ch) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - ch->port = ntohl (msg->port); - channel_set_options (ch, ntohl (msg->opt)); - - /* In unreliable channels, we'll use the DLL to buffer BCK data */ - ch->root_rel = GNUNET_new (struct CadetChannelReliability); - ch->root_rel->ch = ch; - ch->root_rel->retry_timer = CADET_RETRANSMIT_TIME; - ch->root_rel->expected_delay.rel_value_us = 0; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "CREATED CHANNEL %s\n", GMCH_2s (ch)); - - send_create (ch); - - return GNUNET_OK; -} - - -/** - * Handler for cadet network payload traffic. - * - * @param ch Channel for the message. - * @param msg Unencryted data message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -void -GMCH_handle_data (struct CadetChannel *ch, - const struct GNUNET_CADET_Data *msg, - int fwd) -{ - struct CadetChannelReliability *rel; - struct CadetClient *c; - uint32_t mid; - - /* If this is a remote (non-loopback) channel, find 'fwd'. */ - if (GNUNET_SYSERR == fwd) - { - if (is_loopback (ch)) - { - /* It is a loopback channel after all... */ - GNUNET_break (0); - return; - } - fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO; - } - - /* Initialize FWD/BCK data */ - c = fwd ? ch->dest : ch->root; - rel = fwd ? ch->dest_rel : ch->root_rel; - - if (NULL == c) - { - GNUNET_break (GNUNET_NO != ch->destroy); - return; - } - - if (CADET_CHANNEL_READY != ch->state) - { - if (GNUNET_NO == fwd) - { - /* If we are the root, this means the other peer has sent traffic before - * receiving our ACK. Even if the SYNACK goes missing, no traffic should - * be sent before the ACK. - */ - GNUNET_break_op (0); - return; - } - /* If we are the dest, this means that the SYNACK got to the root but - * the ACK went missing. Treat this as an ACK. - */ - channel_confirm (ch, GNUNET_NO); - } - - GNUNET_STATISTICS_update (stats, "# data received", 1, GNUNET_NO); - - mid = ntohl (msg->mid); - LOG (GNUNET_ERROR_TYPE_INFO, "<=== DATA %u %s on channel %s\n", - mid, GM_f2s (fwd), GMCH_2s (ch)); - - if (GNUNET_NO == ch->reliable || - ( !GM_is_pid_bigger (rel->mid_recv, mid) && - GM_is_pid_bigger (rel->mid_recv + 64, mid) ) ) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "RECV %u (%u)\n", - mid, ntohs (msg->header.size)); - if (GNUNET_YES == ch->reliable) - { - /* Is this the exact next expected messasge? */ - if (mid == rel->mid_recv) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "as expected\n"); - rel->mid_recv++; - send_client_data (ch, msg, fwd); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "save for later\n"); - add_buffered_data (msg, rel); - } - } - else - { - /* Tunnel is unreliable: send to clients directly */ - /* FIXME: accept Out Of Order traffic */ - rel->mid_recv = mid + 1; - send_client_data (ch, msg, fwd); - } - } - else - { - GNUNET_break_op (GM_is_pid_bigger (rel->mid_recv, mid)); - LOG (GNUNET_ERROR_TYPE_WARNING, - "MID %u not expected (%u - %u), dropping!\n", - mid, rel->mid_recv, rel->mid_recv + 63); - } - - GMCH_send_data_ack (ch, fwd); -} - - -/** - * Handler for cadet network traffic end-to-end ACKs. - * - * @param ch Channel on which we got this message. - * @param msg Data message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -void -GMCH_handle_data_ack (struct CadetChannel *ch, - const struct GNUNET_CADET_DataACK *msg, - int fwd) -{ - struct CadetChannelReliability *rel; - struct CadetReliableMessage *copy; - struct CadetReliableMessage *next; - uint32_t ack; - int work; - - /* If this is a remote (non-loopback) channel, find 'fwd'. */ - if (GNUNET_SYSERR == fwd) - { - if (is_loopback (ch)) - { - /* It is a loopback channel after all... */ - GNUNET_break (0); - return; - } - /* Inverted: if message came 'FWD' is a 'BCK ACK'. */ - fwd = (NULL != ch->dest) ? GNUNET_NO : GNUNET_YES; - } - - ack = ntohl (msg->mid); - LOG (GNUNET_ERROR_TYPE_INFO, "<=== %s ACK %u\n", GM_f2s (fwd), ack); - - if (GNUNET_YES == fwd) - { - rel = ch->root_rel; - } - else - { - rel = ch->dest_rel; - } - if (NULL == rel) - { - GNUNET_break_op (GNUNET_NO != ch->destroy); - return; - } - - /* Free ACK'd copies: no need to retransmit those anymore FIXME refactor */ - for (work = GNUNET_NO, copy = rel->head_sent; copy != NULL; copy = next) - { - if (GM_is_pid_bigger (copy->mid, ack)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " head %u, out!\n", copy->mid); - channel_rel_free_sent (rel, msg); - break; - } - work = GNUNET_YES; - LOG (GNUNET_ERROR_TYPE_DEBUG, " id %u\n", copy->mid); - next = copy->next; - if (GNUNET_YES == rel_message_free (copy, GNUNET_YES)) - return; - } - - /* ACK client if needed and possible */ - GMCH_allow_client (ch, fwd); - - /* If some message was free'd, update the retransmission delay */ - if (GNUNET_YES == work) - { - if (GNUNET_SCHEDULER_NO_TASK != rel->retry_task) - { - GNUNET_SCHEDULER_cancel (rel->retry_task); - rel->retry_task = GNUNET_SCHEDULER_NO_TASK; - if (NULL != rel->head_sent && NULL == rel->head_sent->chq) - { - struct GNUNET_TIME_Absolute new_target; - struct GNUNET_TIME_Relative delay; - - delay = GNUNET_TIME_relative_multiply (rel->retry_timer, - CADET_RETRANSMIT_MARGIN); - new_target = GNUNET_TIME_absolute_add (rel->head_sent->timestamp, - delay); - delay = GNUNET_TIME_absolute_get_remaining (new_target); - rel->retry_task = - GNUNET_SCHEDULER_add_delayed (delay, - &channel_retransmit_message, - rel); - } - } - else - { - /* Work was done but no task was pending? Shouldn't happen! */ - GNUNET_break (0); - } - } -} - - -/** - * Handler for channel create messages. - * - * Does not have fwd parameter because it's always 'FWD': channel is incoming. - * - * @param t Tunnel this channel will be in. - * @param msg Channel crate message. - */ -struct CadetChannel * -GMCH_handle_create (struct CadetTunnel3 *t, - const struct GNUNET_CADET_ChannelCreate *msg) -{ - CADET_ChannelNumber chid; - struct CadetChannel *ch; - struct CadetClient *c; - int new_channel; - int reaction; - - reaction = GNUNET_NO; - chid = ntohl (msg->chid); - ch = GMT_get_channel (t, chid); - if (NULL == ch) - { - /* Create channel */ - ch = channel_new (t, NULL, 0); - ch->gid = chid; - channel_set_options (ch, ntohl (msg->opt)); - new_channel = GNUNET_YES; - } - else - { - new_channel = GNUNET_NO; - } - - if (GNUNET_YES == new_channel || GMT_is_loopback (t)) - { - /* Find a destination client */ - ch->port = ntohl (msg->port); - LOG (GNUNET_ERROR_TYPE_DEBUG, " port %u\n", ch->port); - c = GML_client_get_by_port (ch->port); - if (NULL == c) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " no client has port registered\n"); - if (is_loopback (ch)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " loopback: destroy on handler\n"); - send_nack (ch); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " not loopback: destroy now\n"); - send_nack (ch); - GMCH_destroy (ch); - } - return NULL; - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " client %p has port registered\n", c); - } - - add_destination (ch, c); - if (GNUNET_YES == ch->reliable) - LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Reliable\n"); - else - LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Not Reliable\n"); - - send_client_create (ch); - ch->state = CADET_CHANNEL_SENT; - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate create channel\n"); - reaction = GNUNET_YES; - if (GNUNET_SCHEDULER_NO_TASK != ch->dest_rel->retry_task) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " clearing retry task\n"); - /* we were waiting to re-send our 'SYNACK', wait no more! */ - GNUNET_SCHEDULER_cancel (ch->dest_rel->retry_task); - ch->dest_rel->retry_task = GNUNET_SCHEDULER_NO_TASK; - } - } - send_ack (ch, GNUNET_YES, reaction); - - return ch; -} - - -/** - * Handler for channel NACK messages. - * - * NACK messages always go dest -> root, no need for 'fwd' or 'msg' parameter. - * - * @param ch Channel. - */ -void -GMCH_handle_nack (struct CadetChannel *ch) -{ - send_client_nack (ch); - GMCH_destroy (ch); -} - - -/** - * Handler for channel ack messages. - * - * @param ch Channel. - * @param msg Message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -void -GMCH_handle_ack (struct CadetChannel *ch, - const struct GNUNET_CADET_ChannelManage *msg, - int fwd) -{ - /* If this is a remote (non-loopback) channel, find 'fwd'. */ - if (GNUNET_SYSERR == fwd) - { - if (is_loopback (ch)) - { - /* It is a loopback channel after all... */ - GNUNET_break (0); - return; - } - fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO; - } - - channel_confirm (ch, !fwd); -} - - -/** - * Handler for channel destroy messages. - * - * @param ch Channel to be destroyed of. - * @param msg Message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -void -GMCH_handle_destroy (struct CadetChannel *ch, - const struct GNUNET_CADET_ChannelManage *msg, - int fwd) -{ - struct CadetChannelReliability *rel; - - /* If this is a remote (non-loopback) channel, find 'fwd'. */ - if (GNUNET_SYSERR == fwd) - { - if (is_loopback (ch)) - { - /* It is a loopback channel after all... */ - GNUNET_break (0); - return; - } - fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO; - } - - GMCH_debug (ch); - if ( (fwd && NULL == ch->dest) || (!fwd && NULL == ch->root) ) - { - /* Not for us (don't destroy twice a half-open loopback channel) */ - return; - } - - rel = fwd ? ch->dest_rel : ch->root_rel; - if (0 == rel->n_recv) - { - send_destroy (ch, GNUNET_YES); - GMCH_destroy (ch); - } - else - { - ch->destroy = GNUNET_YES; - } -} - - -/** - * Sends an already built message on a channel. - * - * If the channel is on a loopback tunnel, notifies the appropriate destination - * client locally. - * - * On a normal channel passes the message to the tunnel for encryption and - * sending on a connection. - * - * This function DOES NOT save the message for retransmission. - * - * @param message Message to send. Function makes a copy of it. - * @param ch Channel on which this message is transmitted. - * @param fwd Is this a fwd message? - * @param existing_copy This is a retransmission, don't save a copy. - */ -void -GMCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message, - struct CadetChannel *ch, int fwd, - void *existing_copy) -{ - struct CadetChannelQueue *chq; - uint16_t type; - - type = ntohs (message->type); - LOG (GNUNET_ERROR_TYPE_INFO, "===> %s %s on channel %s\n", - GM_m2s (type), GM_f2s (fwd), GMCH_2s (ch)); - - if (GMT_is_loopback (ch->t)) - { - handle_loopback (ch, message, fwd); - return; - } - - switch (type) - { - struct GNUNET_CADET_Data *payload; - case GNUNET_MESSAGE_TYPE_CADET_DATA: - - payload = (struct GNUNET_CADET_Data *) message; - LOG (GNUNET_ERROR_TYPE_INFO, "===> %s %u\n", - GM_m2s (type), ntohl (payload->mid)); - if (GNUNET_YES == ch->reliable) - { - chq = GNUNET_new (struct CadetChannelQueue); - chq->type = type; - if (NULL == existing_copy) - chq->copy = channel_save_copy (ch, message, fwd); - else - { - chq->copy = (struct CadetReliableMessage *) existing_copy; - if (NULL != chq->copy->chq) - { - /* Last retransmission was queued but not yet sent! - * This retransmission was scheduled by a ch_message_sent which - * followed a very fast RTT, so the tiny delay made the - * retransmission function to execute before the previous - * retransmitted message even had a chance to leave the peer. - * Cancel this message and wait until the pending - * retransmission leaves the peer and ch_message_sent starts - * the timer for the next one. - */ - GNUNET_free (chq); - LOG (GNUNET_ERROR_TYPE_DEBUG, - " exisitng copy not yet transmitted!\n"); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, - " using existing copy: %p {r:%p q:%p t:%u}\n", - existing_copy, - chq->copy->rel, chq->copy->chq, chq->copy->type); - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " new chq: %p\n", chq); - chq->copy->chq = chq; - chq->tq = GMT_send_prebuilt_message (message, ch->t, NULL, - NULL != existing_copy, - &ch_message_sent, chq); - /* q itself is stored in copy */ - GNUNET_assert (NULL != chq->tq || GNUNET_NO != ch->destroy); - } - else - { - fire_and_forget (message, ch, GNUNET_NO); - } - break; - - - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK: - if (GNUNET_YES == fwd || NULL != existing_copy) - { - /* BCK ACK (going FWD) is just a response for a SYNACK, don't keep*/ - fire_and_forget (message, ch, GNUNET_YES); - return; - } - /* fall-trough */ - case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK: - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE: - chq = GNUNET_new (struct CadetChannelQueue); - chq->type = type; - chq->rel = fwd ? ch->root_rel : ch->dest_rel; - if (NULL != chq->rel->uniq) - { - if (NULL != chq->rel->uniq->tq) - { - GMT_cancel (chq->rel->uniq->tq); - /* ch_message_sent is called, freeing and NULLing uniq */ - } - else - { - GNUNET_break (0); - GNUNET_free (chq->rel->uniq); - } - } - chq->tq = GMT_send_prebuilt_message (message, ch->t, NULL, GNUNET_YES, - &ch_message_sent, chq); - if (NULL == chq->tq) - { - GNUNET_break (0); - GNUNET_free (chq); - chq = NULL; - return; - } - chq->rel->uniq = chq; - break; - - - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK: - fire_and_forget (message, ch, GNUNET_YES); - break; - - - default: - GNUNET_break (0); - LOG (GNUNET_ERROR_TYPE_DEBUG, "type %s unknown!\n", GM_m2s (type)); - fire_and_forget (message, ch, GNUNET_YES); - } -} - - -/** - * Get the static string for identification of the channel. - * - * @param ch Channel. - * - * @return Static string with the channel IDs. - */ -const char * -GMCH_2s (const struct CadetChannel *ch) -{ - static char buf[64]; - - if (NULL == ch) - return "(NULL Channel)"; - - sprintf (buf, "%s:%u gid:%X (%X / %X)", - GMT_2s (ch->t), ch->port, ch->gid, ch->lid_root, ch->lid_dest); - - return buf; -} diff --git a/src/mesh/gnunet-service-cadet_channel.h b/src/mesh/gnunet-service-cadet_channel.h deleted file mode 100644 index f5a89a423..000000000 --- a/src/mesh/gnunet-service-cadet_channel.h +++ /dev/null @@ -1,349 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2013 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 cadet/gnunet-service-cadet_channel.h - * @brief cadet service; dealing with end-to-end channels - * @author Bartlomiej Polot - * - * All functions in this file should use the prefix GMCH (Gnunet Cadet CHannel) - */ - -#ifndef GNUNET_SERVICE_CADET_CHANNEL_H -#define GNUNET_SERVICE_CADET_CHANNEL_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "platform.h" -#include "gnunet_util_lib.h" - -#include "cadet_protocol.h" -#include "cadet.h" - -/** - * Struct containing all information regarding a channel to a remote client. - */ -struct CadetChannel; - - -#include "gnunet-service-cadet_tunnel.h" -#include "gnunet-service-cadet_local.h" - - -/** - * Destroy a channel and free all resources. - * - * @param ch Channel to destroy. - */ -void -GMCH_destroy (struct CadetChannel *ch); - - -/** - * Get the channel's public ID. - * - * @param ch Channel. - * - * @return ID used to identify the channel with the remote peer. - */ -CADET_ChannelNumber -GMCH_get_id (const struct CadetChannel *ch); - -/** - * Get the channel tunnel. - * - * @param ch Channel to get the tunnel from. - * - * @return tunnel of the channel. - */ -struct CadetTunnel3 * -GMCH_get_tunnel (const struct CadetChannel *ch); - -/** - * Get free buffer space towards the client on a specific channel. - * - * @param ch Channel. - * @param fwd Is query about FWD traffic? - * - * @return Free buffer space [0 - 64] - */ -unsigned int -GMCH_get_buffer (struct CadetChannel *ch, int fwd); - - -/** - * Get flow control status of end point: is client allow to send? - * - * @param ch Channel. - * @param fwd Is query about FWD traffic? (Request root status). - * - * @return #GNUNET_YES if client is allowed to send us data. - */ -int -GMCH_get_allowed (struct CadetChannel *ch, int fwd); - - -/** - * Is the root client for this channel on this peer? - * - * @param ch Channel. - * @param fwd Is this for fwd traffic? - * - * @return #GNUNET_YES in case it is. - */ -int -GMCH_is_origin (struct CadetChannel *ch, int fwd); - -/** - * Is the destination client for this channel on this peer? - * - * @param ch Channel. - * @param fwd Is this for fwd traffic? - * - * @return #GNUNET_YES in case it is. - */ -int -GMCH_is_terminal (struct CadetChannel *ch, int fwd); - -/** - * Send an end-to-end ACK message for the most recent in-sequence payload. - * - * If channel is not reliable, do nothing. - * - * @param ch Channel this is about. - * @param fwd Is for FWD traffic? (ACK dest->owner) - */ -void -GMCH_send_data_ack (struct CadetChannel *ch, int fwd); - -/** - * Notify the destination client that a new incoming channel was created. - * - * @param ch Channel that was created. - */ -void -GMCH_send_create (struct CadetChannel *ch); - -/** - * Allow a client to send us more data, in case it was choked. - * - * @param ch Channel. - * @param fwd Is this about FWD traffic? (Root client). - */ -void -GMCH_allow_client (struct CadetChannel *ch, int fwd); - -/** - * Log channel info. - * - * @param ch Channel. - */ -void -GMCH_debug (struct CadetChannel *ch); - -/** - * Handle an ACK given by a client. - * - * Mark client as ready and send him any buffered data we could have for him. - * - * @param ch Channel. - * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by root and go BCK) - */ -void -GMCH_handle_local_ack (struct CadetChannel *ch, int fwd); - -/** - * Handle data given by a client. - * - * Check whether the client is allowed to send in this tunnel, save if channel - * is reliable and send an ACK to the client if there is still buffer space - * in the tunnel. - * - * @param ch Channel. - * @param c Client which sent the data. - * @param message Message. - * @param fwd Is this a FWD data? - * - * @return GNUNET_OK if everything goes well, GNUNET_SYSERR in case of en error. - */ -int -GMCH_handle_local_data (struct CadetChannel *ch, - struct CadetClient *c, - struct GNUNET_MessageHeader *message, - int fwd); - -/** - * Handle a channel destroy requested by a client. - * - * Destroy the channel and the tunnel in case this was the last channel. - * - * @param ch Channel. - * @param c Client that requested the destruction (to avoid notifying him). - * @param is_root Is the request coming from root? - */ -void -GMCH_handle_local_destroy (struct CadetChannel *ch, - struct CadetClient *c, - int is_root); - -/** - * Handle a channel create requested by a client. - * - * Create the channel and the tunnel in case this was the first0 channel. - * - * @param c Client that requested the creation (will be the root). - * @param msg Create Channel message. - * - * @return GNUNET_OK if everything went fine, GNUNET_SYSERR otherwise. - */ -int -GMCH_handle_local_create (struct CadetClient *c, - struct GNUNET_CADET_ChannelMessage *msg); - -/** - * Handler for cadet network payload traffic. - * - * @param ch Channel for the message. - * @param msg Unencryted data message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -void -GMCH_handle_data (struct CadetChannel *ch, - const struct GNUNET_CADET_Data *msg, - int fwd); - -/** - * Handler for cadet network traffic end-to-end ACKs. - * - * @param ch Channel on which we got this message. - * @param msg Data message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -void -GMCH_handle_data_ack (struct CadetChannel *ch, - const struct GNUNET_CADET_DataACK *msg, - int fwd); - -/** - * Handler for channel create messages. - * - * Does not have fwd parameter because it's always 'FWD': channel is incoming. - * - * @param t Tunnel this channel will be in. - * @param msg Channel crate message. - */ -struct CadetChannel * -GMCH_handle_create (struct CadetTunnel3 *t, - const struct GNUNET_CADET_ChannelCreate *msg); - -/** - * Handler for channel NACK messages. - * - * NACK messages always go dest -> root, no need for 'fwd' or 'msg' parameter. - * - * @param ch Channel. - */ -void -GMCH_handle_nack (struct CadetChannel *ch); - -/** - * Handler for channel ack messages. - * - * @param ch Channel this channel is to be created in. - * @param msg Message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -void -GMCH_handle_ack (struct CadetChannel *ch, - const struct GNUNET_CADET_ChannelManage *msg, - int fwd); - -/** - * Handler for channel destroy messages. - * - * @param ch Channel this channel is to be destroyed of. - * @param msg Message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -void -GMCH_handle_destroy (struct CadetChannel *ch, - const struct GNUNET_CADET_ChannelManage *msg, - int fwd); - -/** - * Sends an already built message on a channel. - * - * If the channel is on a loopback tunnel, notifies the appropriate destination - * client locally. - * - * On a normal channel passes the message to the tunnel for encryption and - * sending on a connection. - * - * This function DOES NOT save the message for retransmission. - * - * @param message Message to send. Function makes a copy of it. - * @param ch Channel on which this message is transmitted. - * @param fwd Is this a fwd message? - * @param existing_copy This is a retransmission, don't save a copy. - */ -void -GMCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message, - struct CadetChannel *ch, int fwd, - void *existing_copy); - -/** - * Get the static string for identification of the channel. - * - * @param ch Channel.i - * - * @return Static string with the channel IDs. - */ -const char * -GMCH_2s (const struct CadetChannel *ch); - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_SERVICE_CADET_CHANNEL_H */ -#endif -/* end of gnunet-service-cadet_channel.h */ diff --git a/src/mesh/gnunet-service-cadet_connection.c b/src/mesh/gnunet-service-cadet_connection.c deleted file mode 100644 index 9c07e006b..000000000 --- a/src/mesh/gnunet-service-cadet_connection.c +++ /dev/null @@ -1,3176 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2001-2013 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 cadet/gnunet-service-cadet_connection.c - * @brief GNUnet CADET service connection handling - * @author Bartlomiej Polot - */ - -#include "platform.h" -#include "gnunet_util_lib.h" - -#include "gnunet_statistics_service.h" - -#include "cadet_path.h" -#include "cadet_protocol.h" -#include "cadet.h" -#include "gnunet-service-cadet_connection.h" -#include "gnunet-service-cadet_peer.h" -#include "gnunet-service-cadet_tunnel.h" - - -#define LOG(level, ...) GNUNET_log_from (level,"cadet-con",__VA_ARGS__) - -#define CADET_MAX_POLL_TIME GNUNET_TIME_relative_multiply (\ - GNUNET_TIME_UNIT_MINUTES,\ - 10) -#define AVG_MSGS 32 - - -/******************************************************************************/ -/******************************** STRUCTS **********************************/ -/******************************************************************************/ - -/** - * Struct to encapsulate all the Flow Control information to a peer to which - * we are directly connected (on a core level). - */ -struct CadetFlowControl -{ - /** - * Connection this controls. - */ - struct CadetConnection *c; - - /** - * How many messages are in the queue on this connection. - */ - unsigned int queue_n; - - /** - * How many messages do we accept in the queue. - */ - unsigned int queue_max; - - /** - * ID of the last packet sent towards the peer. - */ - uint32_t last_pid_sent; - - /** - * ID of the last packet received from the peer. - */ - uint32_t last_pid_recv; - - /** - * Last ACK sent to the peer (peer can't send more than this PID). - */ - uint32_t last_ack_sent; - - /** - * Last ACK sent towards the origin (for traffic towards leaf node). - */ - uint32_t last_ack_recv; - - /** - * Task to poll the peer in case of a lost ACK causes stall. - */ - GNUNET_SCHEDULER_TaskIdentifier poll_task; - - /** - * How frequently to poll for ACKs. - */ - struct GNUNET_TIME_Relative poll_time; - - /** - * Queued poll message, to cancel if not necessary anymore (got ACK). - */ - struct CadetConnectionQueue *poll_msg; - - /** - * Queued poll message, to cancel if not necessary anymore (got ACK). - */ - struct CadetConnectionQueue *ack_msg; -}; - -/** - * Keep a record of the last messages sent on this connection. - */ -struct CadetConnectionPerformance -{ - /** - * Circular buffer for storing measurements. - */ - double usecsperbyte[AVG_MSGS]; - - /** - * Running average of @c usecsperbyte. - */ - double avg; - - /** - * How many values of @c usecsperbyte are valid. - */ - uint16_t size; - - /** - * Index of the next "free" position in @c usecsperbyte. - */ - uint16_t idx; -}; - - -/** - * Struct containing all information regarding a connection to a peer. - */ -struct CadetConnection -{ - /** - * Tunnel this connection is part of. - */ - struct CadetTunnel3 *t; - - /** - * Flow control information for traffic fwd. - */ - struct CadetFlowControl fwd_fc; - - /** - * Flow control information for traffic bck. - */ - struct CadetFlowControl bck_fc; - - /** - * Measure connection performance on the endpoint. - */ - struct CadetConnectionPerformance *perf; - - /** - * ID of the connection. - */ - struct GNUNET_CADET_Hash id; - - /** - * State of the connection. - */ - enum CadetConnectionState state; - - /** - * Path being used for the tunnel. At the origin of the connection - * it's a pointer to the destination's path pool, otherwise just a copy. - */ - struct CadetPeerPath *path; - - /** - * Position of the local peer in the path. - */ - unsigned int own_pos; - - /** - * Task to keep the used paths alive at the owner, - * time tunnel out on all the other peers. - */ - GNUNET_SCHEDULER_TaskIdentifier fwd_maintenance_task; - - /** - * Task to keep the used paths alive at the destination, - * time tunnel out on all the other peers. - */ - GNUNET_SCHEDULER_TaskIdentifier bck_maintenance_task; - - /** - * Queue handle for maintainance traffic. One handle for FWD and BCK since - * one peer never needs to maintain both directions (no loopback connections). - */ - struct CadetPeerQueue *maintenance_q; - - /** - * Counter to do exponential backoff when creating a connection (max 64). - */ - unsigned short create_retry; - - /** - * Pending message count. - */ - int pending_messages; - - /** - * Destroy flag: if true, destroy on last message. - */ - int destroy; -}; - -/** - * Handle for messages queued but not yet sent. - */ -struct CadetConnectionQueue -{ - /** - * Peer queue handle, to cancel if necessary. - */ - struct CadetPeerQueue *q; - - /** - * Was this a forced message? (Do not account for it) - */ - int forced; - - /** - * Continuation to call once sent. - */ - GMC_sent cont; - - /** - * Closure for @c cont. - */ - void *cont_cls; -}; - -/******************************************************************************/ -/******************************* GLOBALS ***********************************/ -/******************************************************************************/ - -/** - * Global handle to the statistics service. - */ -extern struct GNUNET_STATISTICS_Handle *stats; - -/** - * Local peer own ID (memory efficient handle). - */ -extern GNUNET_PEER_Id myid; - -/** - * Local peer own ID (full value). - */ -extern struct GNUNET_PeerIdentity my_full_id; - -/** - * Connections known, indexed by cid (CadetConnection). - */ -static struct GNUNET_CONTAINER_MultiHashMap *connections; - -/** - * How many connections are we willing to maintain. - * Local connections are always allowed, even if there are more connections than max. - */ -static unsigned long long max_connections; - -/** - * How many messages *in total* are we willing to queue, divide by number of - * connections to get connection queue size. - */ -static unsigned long long max_msgs_queue; - -/** - * How often to send path keepalives. Paths timeout after 4 missed. - */ -static struct GNUNET_TIME_Relative refresh_connection_time; - -/** - * How often to send path create / ACKs. - */ -static struct GNUNET_TIME_Relative create_connection_time; - - -/******************************************************************************/ -/******************************** STATIC ***********************************/ -/******************************************************************************/ - -#if 0 // avoid compiler warning for unused static function -static void -fc_debug (struct CadetFlowControl *fc) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, " IN: %u/%u\n", - fc->last_pid_recv, fc->last_ack_sent); - LOG (GNUNET_ERROR_TYPE_DEBUG, " OUT: %u/%u\n", - fc->last_pid_sent, fc->last_ack_recv); - LOG (GNUNET_ERROR_TYPE_DEBUG, " QUEUE: %u/%u\n", - fc->queue_n, fc->queue_max); -} - -static void -connection_debug (struct CadetConnection *c) -{ - if (NULL == c) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "*** DEBUG NULL CONNECTION ***\n"); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s:%X\n", - peer2s (c->t->peer), GMC_2s (c)); - LOG (GNUNET_ERROR_TYPE_DEBUG, " state: %u, pending msgs: %u\n", - c->state, c->pending_messages); - LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD FC\n"); - fc_debug (&c->fwd_fc); - LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK FC\n"); - fc_debug (&c->bck_fc); -} -#endif - - -/** - * Schedule next keepalive task, taking in consideration - * the connection state and number of retries. - * - * @param c Connection for which to schedule the next keepalive. - * @param fwd Direction for the next keepalive. - */ -static void -schedule_next_keepalive (struct CadetConnection *c, int fwd); - - -/** - * Resets the connection timeout task, some other message has done the - * task's job. - * - For the first peer on the direction this means to send - * a keepalive or a path confirmation message (either create or ACK). - * - For all other peers, this means to destroy the connection, - * due to lack of activity. - * Starts the timeout if no timeout was running (connection just created). - * - * @param c Connection whose timeout to reset. - * @param fwd Is this forward? - */ -static void -connection_reset_timeout (struct CadetConnection *c, int fwd); - - -/** - * Get string description for tunnel state. Reentrant. - * - * @param s Tunnel state. - * - * @return String representation. - */ -static const char * -GMC_state2s (enum CadetConnectionState s) -{ - switch (s) - { - case CADET_CONNECTION_NEW: - return "CADET_CONNECTION_NEW"; - case CADET_CONNECTION_SENT: - return "CADET_CONNECTION_SENT"; - case CADET_CONNECTION_ACK: - return "CADET_CONNECTION_ACK"; - case CADET_CONNECTION_READY: - return "CADET_CONNECTION_READY"; - case CADET_CONNECTION_DESTROYED: - return "CADET_CONNECTION_DESTROYED"; - default: - return "CADET_CONNECTION_STATE_ERROR"; - } -} - - -/** - * Initialize a Flow Control structure to the initial state. - * - * @param fc Flow Control structure to initialize. - */ -static void -fc_init (struct CadetFlowControl *fc) -{ - fc->last_pid_sent = (uint32_t) -1; /* Next (expected) = 0 */ - fc->last_pid_recv = (uint32_t) -1; - fc->last_ack_sent = (uint32_t) 0; - fc->last_ack_recv = (uint32_t) 0; - fc->poll_task = GNUNET_SCHEDULER_NO_TASK; - fc->poll_time = GNUNET_TIME_UNIT_SECONDS; - fc->queue_n = 0; - fc->queue_max = (max_msgs_queue / max_connections) + 1; -} - - -/** - * Find a connection. - * - * @param cid Connection ID. - */ -static struct CadetConnection * -connection_get (const struct GNUNET_CADET_Hash *cid) -{ - return GNUNET_CONTAINER_multihashmap_get (connections, GM_h2hc (cid)); -} - - -static void -connection_change_state (struct CadetConnection* c, - enum CadetConnectionState state) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Connection %s state %s -> %s\n", - GMC_2s (c), GMC_state2s (c->state), GMC_state2s (state)); - if (CADET_CONNECTION_DESTROYED == c->state) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "state not changing anymore\n"); - return; - } - c->state = state; - if (CADET_CONNECTION_READY == state) - c->create_retry = 1; -} - - -/** - * Callback called when a queued ACK message is sent. - * - * @param cls Closure (FC). - * @param c Connection this message was on. - * @param q Queue handler this call invalidates. - * @param type Type of message sent. - * @param fwd Was this a FWD going message? - * @param size Size of the message. - */ -static void -ack_sent (void *cls, - struct CadetConnection *c, - struct CadetConnectionQueue *q, - uint16_t type, int fwd, size_t size) -{ - struct CadetFlowControl *fc = cls; - - fc->ack_msg = NULL; -} - - -/** - * Send an ACK on the connection, informing the predecessor about - * the available buffer space. Should not be called in case the peer - * is origin (no predecessor) in the @c fwd direction. - * - * Note that for fwd ack, the FWD mean forward *traffic* (root->dest), - * the ACK itself goes "back" (dest->root). - * - * @param c Connection on which to send the ACK. - * @param buffer How much space free to advertise? - * @param fwd Is this FWD ACK? (Going dest -> root) - * @param force Don't optimize out. - */ -static void -send_ack (struct CadetConnection *c, unsigned int buffer, int fwd, int force) -{ - struct CadetFlowControl *next_fc; - struct CadetFlowControl *prev_fc; - struct GNUNET_CADET_ACK msg; - uint32_t ack; - int delta; - - /* If origin, there is no connection to send ACKs. Wrong function! */ - if (GMC_is_origin (c, fwd)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "connection %s is origin in %s\n", - GMC_2s (c), GM_f2s (fwd)); - GNUNET_break (0); - return; - } - - next_fc = fwd ? &c->fwd_fc : &c->bck_fc; - prev_fc = fwd ? &c->bck_fc : &c->fwd_fc; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "connection send %s ack on %s\n", - GM_f2s (fwd), GMC_2s (c)); - - /* Check if we need to transmit the ACK. */ - delta = prev_fc->last_ack_sent - prev_fc->last_pid_recv; - if (3 < delta && buffer < delta && GNUNET_NO == force) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending ACK, buffer > 3\n"); - LOG (GNUNET_ERROR_TYPE_DEBUG, - " last pid recv: %u, last ack sent: %u\n", - prev_fc->last_pid_recv, prev_fc->last_ack_sent); - return; - } - - /* Ok, ACK might be necessary, what PID to ACK? */ - ack = prev_fc->last_pid_recv + buffer; - LOG (GNUNET_ERROR_TYPE_DEBUG, " ACK %u\n", ack); - LOG (GNUNET_ERROR_TYPE_DEBUG, - " last pid %u, last ack %u, qmax %u, q %u\n", - prev_fc->last_pid_recv, prev_fc->last_ack_sent, - next_fc->queue_max, next_fc->queue_n); - if (ack == prev_fc->last_ack_sent && GNUNET_NO == force) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending FWD ACK, not needed\n"); - return; - } - - /* Check if message is already in queue */ - if (NULL != prev_fc->ack_msg) - { - if (GM_is_pid_bigger (ack, prev_fc->last_ack_sent)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " canceling old ACK\n"); - GMC_cancel (prev_fc->ack_msg); - /* GMC_cancel triggers ack_sent(), which clears fc->ack_msg */ - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " same ACK already in queue\n"); - return; - } - } - - prev_fc->last_ack_sent = ack; - - /* Build ACK message and send on connection */ - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_ACK); - msg.ack = htonl (ack); - msg.cid = c->id; - - prev_fc->ack_msg = GMC_send_prebuilt_message (&msg.header, - GNUNET_MESSAGE_TYPE_CADET_ACK, - ack, c, !fwd, GNUNET_YES, - &ack_sent, prev_fc); -} - - -/** - * Callback called when a connection queued message is sent. - * - * Calculates the average time and connection packet tracking. - * - * @param cls Closure (ConnectionQueue Handle). - * @param c Connection this message was on. - * @param sent Was it really sent? (Could have been canceled) - * @param type Type of message sent. - * @param pid Packet ID, or 0 if not applicable (create, destroy, etc). - * @param fwd Was this a FWD going message? - * @param size Size of the message. - * @param wait Time spent waiting for core (only the time for THIS message) - */ -static void -conn_message_sent (void *cls, - struct CadetConnection *c, int sent, - uint16_t type, uint32_t pid, int fwd, size_t size, - struct GNUNET_TIME_Relative wait) -{ - struct CadetConnectionPerformance *p; - struct CadetFlowControl *fc; - struct CadetConnectionQueue *q = cls; - double usecsperbyte; - int forced; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "connection message_sent\n"); - - fc = fwd ? &c->fwd_fc : &c->bck_fc; - LOG (GNUNET_ERROR_TYPE_DEBUG, " %ssent %s %s\n", - sent ? "" : "not ", GM_f2s (fwd), GM_m2s (type)); - if (NULL != q) - { - forced = q->forced; - if (NULL != q->cont) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " calling cont\n"); - q->cont (q->cont_cls, c, q, type, fwd, size); - } - GNUNET_free (q); - } - else if (type == GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED) - { - /* If NULL == q and ENCRYPTED == type, message must have been ch_mngmnt */ - forced = GNUNET_YES; - } - else - { - forced = GNUNET_NO; - } - if (NULL == c) - { - GNUNET_break (type == GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN || - type == GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY); - LOG (GNUNET_ERROR_TYPE_ERROR, "Message %s sent on NULL connection!\n", - GM_m2s (type)); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P- %p %u\n", c, c->pending_messages); - c->pending_messages--; - if (GNUNET_YES == c->destroy && 0 == c->pending_messages) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "! destroying connection!\n"); - GMC_destroy (c); - return; - } - /* Send ACK if needed, after accounting for sent ID in fc->queue_n */ - switch (type) - { - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE: - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK: - c->maintenance_q = NULL; - /* Don't trigger a keepalive for sent ACKs, only SYN and SYNACKs */ - if (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE == type || !fwd) - schedule_next_keepalive (c, fwd); - break; - - case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED: - if (GNUNET_YES == sent) - { - GNUNET_assert (NULL != q); - fc->last_pid_sent = pid; // FIXME - GMC_send_ack (c, fwd, GNUNET_NO); - connection_reset_timeout (c, fwd); - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, "! Q_N- %p %u\n", fc, fc->queue_n); - if (GNUNET_NO == forced) - { - fc->queue_n--; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "! accounting pid %u\n", - fc->last_pid_sent); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "! forced, Q_N not accounting pid %u\n", - fc->last_pid_sent); - } - break; - - case GNUNET_MESSAGE_TYPE_CADET_KX: - if (GNUNET_YES == sent) - connection_reset_timeout (c, fwd); - break; - - case GNUNET_MESSAGE_TYPE_CADET_POLL: - fc->poll_msg = NULL; - break; - - case GNUNET_MESSAGE_TYPE_CADET_ACK: - fc->ack_msg = NULL; - break; - - default: - break; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, "! message sent!\n"); - - if (NULL == c->perf) - return; /* Only endpoints are interested in timing. */ - - p = c->perf; - usecsperbyte = ((double) wait.rel_value_us) / size; - if (p->size == AVG_MSGS) - { - /* Array is full. Substract oldest value, add new one and store. */ - p->avg -= (p->usecsperbyte[p->idx] / AVG_MSGS); - p->usecsperbyte[p->idx] = usecsperbyte; - p->avg += (p->usecsperbyte[p->idx] / AVG_MSGS); - } - else - { - /* Array not yet full. Add current value to avg and store. */ - p->usecsperbyte[p->idx] = usecsperbyte; - p->avg *= p->size; - p->avg += p->usecsperbyte[p->idx]; - p->size++; - p->avg /= p->size; - } - p->idx = (p->idx + 1) % AVG_MSGS; -} - - -/** - * Get the previous hop in a connection - * - * @param c Connection. - * - * @return Previous peer in the connection. - */ -static struct CadetPeer * -get_prev_hop (const struct CadetConnection *c) -{ - GNUNET_PEER_Id id; - - LOG (GNUNET_ERROR_TYPE_DEBUG, " get prev hop %s [%u/%u]\n", - GMC_2s (c), c->own_pos, c->path->length); - if (0 == c->own_pos || c->path->length < 2) - id = c->path->peers[0]; - else - id = c->path->peers[c->own_pos - 1]; - - LOG (GNUNET_ERROR_TYPE_DEBUG, " ID: %s (%u)\n", - GNUNET_i2s (GNUNET_PEER_resolve2 (id)), id); - - return GMP_get_short (id); -} - - -/** - * Get the next hop in a connection - * - * @param c Connection. - * - * @return Next peer in the connection. - */ -static struct CadetPeer * -get_next_hop (const struct CadetConnection *c) -{ - GNUNET_PEER_Id id; - - LOG (GNUNET_ERROR_TYPE_DEBUG, " get next hop %s [%u/%u]\n", - GMC_2s (c), c->own_pos, c->path->length); - if ((c->path->length - 1) == c->own_pos || c->path->length < 2) - id = c->path->peers[c->path->length - 1]; - else - id = c->path->peers[c->own_pos + 1]; - - LOG (GNUNET_ERROR_TYPE_DEBUG, " ID: %s (%u)\n", - GNUNET_i2s (GNUNET_PEER_resolve2 (id)), id); - - return GMP_get_short (id); -} - - -/** - * Get the hop in a connection. - * - * @param c Connection. - * @param fwd Next hop? - * - * @return Next peer in the connection. - */ -static struct CadetPeer * -get_hop (struct CadetConnection *c, int fwd) -{ - if (fwd) - return get_next_hop (c); - return get_prev_hop (c); -} - - -/** - * Is traffic coming from this sender 'FWD' traffic? - * - * @param c Connection to check. - * @param sender Peer identity of neighbor. - * - * @return #GNUNET_YES in case the sender is the 'prev' hop and therefore - * the traffic is 'FWD'. - * #GNUNET_NO for BCK. - * #GNUNET_SYSERR for errors. - */ -static int -is_fwd (const struct CadetConnection *c, - const struct GNUNET_PeerIdentity *sender) -{ - GNUNET_PEER_Id id; - - id = GNUNET_PEER_search (sender); - if (GMP_get_short_id (get_prev_hop (c)) == id) - return GNUNET_YES; - - if (GMP_get_short_id (get_next_hop (c)) == id) - return GNUNET_NO; - - GNUNET_break (0); - return GNUNET_SYSERR; -} - - -/** - * Sends a CONNECTION ACK message in reponse to a received CONNECTION_CREATE - * or a first CONNECTION_ACK directed to us. - * - * @param connection Connection to confirm. - * @param fwd Should we send it FWD? (root->dest) - * (First (~SYNACK) goes BCK, second (~ACK) goes FWD) - */ -static void -send_connection_ack (struct CadetConnection *connection, int fwd) -{ - struct CadetTunnel3 *t; - - t = connection->t; - LOG (GNUNET_ERROR_TYPE_INFO, "===> {%14s ACK} on connection %s\n", - GM_f2s (!fwd), GMC_2s (connection)); - GMP_queue_add (get_hop (connection, fwd), NULL, - GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK, - GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK, 0, - sizeof (struct GNUNET_CADET_ConnectionACK), - connection, fwd, &conn_message_sent, NULL); - connection->pending_messages++; - if (CADET_TUNNEL3_NEW == GMT_get_cstate (t)) - GMT_change_cstate (t, CADET_TUNNEL3_WAITING); - if (CADET_CONNECTION_READY != connection->state) - connection_change_state (connection, CADET_CONNECTION_SENT); -} - - -/** - * Send a notification that a connection is broken. - * - * @param c Connection that is broken. - * @param id1 Peer that has disconnected. - * @param id2 Peer that has disconnected. - * @param fwd Direction towards which to send it. - */ -static void -send_broken (struct CadetConnection *c, - const struct GNUNET_PeerIdentity *id1, - const struct GNUNET_PeerIdentity *id2, - int fwd) -{ - struct GNUNET_CADET_ConnectionBroken msg; - - msg.header.size = htons (sizeof (struct GNUNET_CADET_ConnectionBroken)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN); - msg.cid = c->id; - msg.peer1 = *id1; - msg.peer2 = *id2; - GMC_send_prebuilt_message (&msg.header, - GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN, 0, - c, fwd, GNUNET_YES, NULL, NULL); -} - - -/** - * Send a notification that a connection is broken, when a connection - * isn't even known to the local peer. - * - * @param connection_id Connection ID. - * @param id1 Peer that has disconnected, probably local peer. - * @param id2 Peer that has disconnected can be NULL if unknown. - * @param peer Peer to notify (neighbor who sent the connection). - */ -static void -send_broken_unknown (const struct GNUNET_CADET_Hash *connection_id, - const struct GNUNET_PeerIdentity *id1, - const struct GNUNET_PeerIdentity *id2, - const struct GNUNET_PeerIdentity *peer_id) -{ - struct GNUNET_CADET_ConnectionBroken *msg; - struct CadetPeer *neighbor; - - LOG (GNUNET_ERROR_TYPE_INFO, "===> BROKEN on unknown connection %s\n", - GNUNET_h2s (GM_h2hc (connection_id))); - - msg = GNUNET_new (struct GNUNET_CADET_ConnectionBroken); - msg->header.size = htons (sizeof (struct GNUNET_CADET_ConnectionBroken)); - msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN); - msg->cid = *connection_id; - msg->peer1 = *id1; - if (NULL != id2) - msg->peer2 = *id2; - else - memset (&msg->peer2, 0, sizeof (msg->peer2)); - neighbor = GMP_get (peer_id); - GMP_queue_add (neighbor, msg, - GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN, - GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN, 2, - sizeof (struct GNUNET_CADET_ConnectionBroken), - NULL, GNUNET_SYSERR, /* connection, fwd */ - NULL, NULL); /* continuation */ -} - - -/** - * Send keepalive packets for a connection. - * - * @param c Connection to keep alive.. - * @param fwd Is this a FWD keepalive? (owner -> dest). - */ -static void -send_connection_keepalive (struct CadetConnection *c, int fwd) -{ - struct GNUNET_MessageHeader msg; - struct CadetFlowControl *fc; - - LOG (GNUNET_ERROR_TYPE_INFO, - "keepalive %s for connection %s\n", - GM_f2s (fwd), GMC_2s (c)); - - fc = fwd ? &c->fwd_fc : &c->bck_fc; - if (0 < fc->queue_n) - { - LOG (GNUNET_ERROR_TYPE_INFO, "not sending keepalive, traffic in queue\n"); - } - - GNUNET_STATISTICS_update (stats, "# keepalives sent", 1, GNUNET_NO); - - GNUNET_assert (NULL != c->t); - msg.size = htons (sizeof (msg)); - msg.type = htons (GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE); - - GNUNET_assert (NULL == - GMT_send_prebuilt_message (&msg, c->t, c, - GNUNET_NO, NULL, NULL)); -} - - -/** - * Send CONNECTION_{CREATE/ACK} packets for a connection. - * - * @param c Connection for which to send the message. - * @param fwd If #GNUNET_YES, send CREATE, otherwise send ACK. - */ -static void -connection_recreate (struct CadetConnection *c, int fwd) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "sending connection recreate\n"); - if (fwd) - GMC_send_create (c); - else - send_connection_ack (c, GNUNET_NO); -} - - -/** - * Generic connection timer management. - * Depending on the role of the peer in the connection will send the - * appropriate message (build or keepalive) - * - * @param c Conncetion to maintain. - * @param fwd Is FWD? - */ -static void -connection_maintain (struct CadetConnection *c, int fwd) -{ - if (GNUNET_NO != c->destroy) - return; - - if (CADET_TUNNEL3_SEARCHING == GMT_get_cstate (c->t)) - { - /* TODO DHT GET with RO_BART */ - return; - } - switch (c->state) - { - case CADET_CONNECTION_NEW: - GNUNET_break (0); - /* fall-through */ - case CADET_CONNECTION_SENT: - connection_recreate (c, fwd); - break; - case CADET_CONNECTION_READY: - send_connection_keepalive (c, fwd); - break; - default: - break; - } -} - - - -/** - * Keep the connection alive. - * - * @param c Connection to keep alive. - * @param fwd Direction. - * @param shutdown Are we shutting down? (Don't send traffic) - * Non-zero value for true, not necessarily GNUNET_YES. - */ -static void -connection_keepalive (struct CadetConnection *c, int fwd, int shutdown) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "%s keepalive for %s\n", - GM_f2s (fwd), GMC_2s (c)); - - if (fwd) - c->fwd_maintenance_task = GNUNET_SCHEDULER_NO_TASK; - else - c->bck_maintenance_task = GNUNET_SCHEDULER_NO_TASK; - - if (GNUNET_NO != shutdown) - return; - - connection_maintain (c, fwd); - - /* Next execution will be scheduled by message_sent */ -} - - -/** - * Keep the connection alive in the FWD direction. - * - * @param cls Closure (connection to keepalive). - * @param tc TaskContext. - */ -static void -connection_fwd_keepalive (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - connection_keepalive ((struct CadetConnection *) cls, - GNUNET_YES, - tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN); -} - - -/** - * Keep the connection alive in the BCK direction. - * - * @param cls Closure (connection to keepalive). - * @param tc TaskContext. - */ -static void -connection_bck_keepalive (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - connection_keepalive ((struct CadetConnection *) cls, - GNUNET_NO, - tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN); -} - - -/** - * Schedule next keepalive task, taking in consideration - * the connection state and number of retries. - * - * If the peer is not the origin, do nothing. - * - * @param c Connection for which to schedule the next keepalive. - * @param fwd Direction for the next keepalive. - */ -static void -schedule_next_keepalive (struct CadetConnection *c, int fwd) -{ - struct GNUNET_TIME_Relative delay; - GNUNET_SCHEDULER_TaskIdentifier *task_id; - GNUNET_SCHEDULER_Task keepalive_task; - - if (GNUNET_NO == GMC_is_origin (c, fwd)) - return; - - /* Calculate delay to use, depending on the state of the connection */ - if (CADET_CONNECTION_READY == c->state) - { - delay = refresh_connection_time; - } - else - { - if (1 > c->create_retry) - c->create_retry = 1; - delay = GNUNET_TIME_relative_multiply (create_connection_time, - c->create_retry); - if (c->create_retry < 64) - c->create_retry *= 2; - } - - /* Select direction-dependent parameters */ - if (GNUNET_YES == fwd) - { - task_id = &c->fwd_maintenance_task; - keepalive_task = &connection_fwd_keepalive; - } - else - { - task_id = &c->bck_maintenance_task; - keepalive_task = &connection_bck_keepalive; - } - - /* Check that no one scheduled it before us */ - if (GNUNET_SCHEDULER_NO_TASK != *task_id) - { - /* No need for a _break. It can happen for instance when sending a SYNACK - * for a duplicate SYN: the first SYNACK scheduled the task. */ - GNUNET_SCHEDULER_cancel (*task_id); - } - - /* Schedule the task */ - *task_id = GNUNET_SCHEDULER_add_delayed (delay, keepalive_task, c); - LOG (GNUNET_ERROR_TYPE_DEBUG, "next keepalive in %s\n", - GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES)); -} - - -/** - * @brief Re-initiate traffic on this connection if necessary. - * - * Check if there is traffic queued towards this peer - * and the core transmit handle is NULL (traffic was stalled). - * If so, call core tmt rdy. - * - * @param c Connection on which initiate traffic. - * @param fwd Is this about fwd traffic? - */ -static void -connection_unlock_queue (struct CadetConnection *c, int fwd) -{ - struct CadetPeer *peer; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "connection_unlock_queue %s on %s\n", - GM_f2s (fwd), GMC_2s (c)); - - if (GMC_is_terminal (c, fwd)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " is terminal!\n"); - return; - } - - peer = get_hop (c, fwd); - GMP_queue_unlock (peer, c); -} - - -/** - * Cancel all transmissions that belong to a certain connection. - * - * If the connection is scheduled for destruction and no more messages are left, - * the connection will be destroyed by the continuation call. - * - * @param c Connection which to cancel. Might be destroyed during this call. - * @param fwd Cancel fwd traffic? - */ -static void -connection_cancel_queues (struct CadetConnection *c, int fwd) -{ - struct CadetFlowControl *fc; - struct CadetPeer *peer; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - " *** Cancel %s queues for connection %s\n", - GM_f2s (fwd), GMC_2s (c)); - if (NULL == c) - { - GNUNET_break (0); - return; - } - - fc = fwd ? &c->fwd_fc : &c->bck_fc; - if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task) - { - GNUNET_SCHEDULER_cancel (fc->poll_task); - fc->poll_task = GNUNET_SCHEDULER_NO_TASK; - LOG (GNUNET_ERROR_TYPE_DEBUG, " *** Cancel POLL in ccq for fc %p\n", fc); - } - peer = get_hop (c, fwd); - GMP_queue_cancel (peer, c); -} - - -/** - * Function called if a connection has been stalled for a while, - * possibly due to a missed ACK. Poll the neighbor about its ACK status. - * - * @param cls Closure (poll ctx). - * @param tc TaskContext. - */ -static void -connection_poll (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - - -/** - * Callback called when a queued POLL message is sent. - * - * @param cls Closure (FC). - * @param c Connection this message was on. - * @param q Queue handler this call invalidates. - * @param type Type of message sent. - * @param fwd Was this a FWD going message? - * @param size Size of the message. - */ -static void -poll_sent (void *cls, - struct CadetConnection *c, - struct CadetConnectionQueue *q, - uint16_t type, int fwd, size_t size) -{ - struct CadetFlowControl *fc = cls; - - if (2 == c->destroy) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL canceled on shutdown\n"); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, - " *** POLL sent for , scheduling new one!\n"); - fc->poll_msg = NULL; - fc->poll_time = GNUNET_TIME_STD_BACKOFF (fc->poll_time); - fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time, - &connection_poll, fc); - LOG (GNUNET_ERROR_TYPE_DEBUG, " task %u\n", fc->poll_task); - -} - -/** - * Function called if a connection has been stalled for a while, - * possibly due to a missed ACK. Poll the neighbor about its ACK status. - * - * @param cls Closure (poll ctx). - * @param tc TaskContext. - */ -static void -connection_poll (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct CadetFlowControl *fc = cls; - struct GNUNET_CADET_Poll msg; - struct CadetConnection *c; - - fc->poll_task = GNUNET_SCHEDULER_NO_TASK; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - { - return; - } - - c = fc->c; - LOG (GNUNET_ERROR_TYPE_DEBUG, " *** Polling connection %s %s\n", - GMC_2s (c), fc == &c->fwd_fc ? "FWD" : "BCK"); - - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_POLL); - msg.header.size = htons (sizeof (msg)); - msg.pid = htonl (fc->last_pid_sent); - LOG (GNUNET_ERROR_TYPE_DEBUG, " *** last pid sent: %u!\n", fc->last_pid_sent); - fc->poll_msg = - GMC_send_prebuilt_message (&msg.header, - GNUNET_MESSAGE_TYPE_CADET_POLL, - fc->last_pid_sent, - c, fc == &c->fwd_fc, GNUNET_YES, - &poll_sent, fc); -} - - -/** - * Timeout function due to lack of keepalive/traffic from the owner. - * Destroys connection if called. - * - * @param cls Closure (connection to destroy). - * @param tc TaskContext. - */ -static void -connection_fwd_timeout (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct CadetConnection *c = cls; - - c->fwd_maintenance_task = GNUNET_SCHEDULER_NO_TASK; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s FWD timed out. Destroying.\n", - GMC_2s (c)); - if (GMC_is_origin (c, GNUNET_YES)) /* If local, leave. */ - { - GNUNET_break (0); - return; - } - - GMC_destroy (c); -} - - -/** - * Timeout function due to lack of keepalive/traffic from the destination. - * Destroys connection if called. - * - * @param cls Closure (connection to destroy). - * @param tc TaskContext - */ -static void -connection_bck_timeout (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct CadetConnection *c = cls; - - c->bck_maintenance_task = GNUNET_SCHEDULER_NO_TASK; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s BCK timed out. Destroying.\n", - GMC_2s (c)); - - if (GMC_is_origin (c, GNUNET_NO)) /* If local, leave. */ - { - GNUNET_break (0); - return; - } - - GMC_destroy (c); -} - - -/** - * Resets the connection timeout task, some other message has done the - * task's job. - * - For the first peer on the direction this means to send - * a keepalive or a path confirmation message (either create or ACK). - * - For all other peers, this means to destroy the connection, - * due to lack of activity. - * Starts the timeout if no timeout was running (connection just created). - * - * @param c Connection whose timeout to reset. - * @param fwd Is this forward? - * - * TODO use heap to improve efficiency of scheduler. - */ -static void -connection_reset_timeout (struct CadetConnection *c, int fwd) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s reset timeout\n", GM_f2s (fwd)); - - if (GMC_is_origin (c, fwd)) /* Startpoint */ - { - schedule_next_keepalive (c, fwd); - } - else /* Relay, endpoint. */ - { - struct GNUNET_TIME_Relative delay; - GNUNET_SCHEDULER_TaskIdentifier *ti; - GNUNET_SCHEDULER_Task f; - - ti = fwd ? &c->fwd_maintenance_task : &c->bck_maintenance_task; - - if (GNUNET_SCHEDULER_NO_TASK != *ti) - GNUNET_SCHEDULER_cancel (*ti); - delay = GNUNET_TIME_relative_multiply (refresh_connection_time, 4); - f = fwd ? &connection_fwd_timeout : &connection_bck_timeout; - *ti = GNUNET_SCHEDULER_add_delayed (delay, f, c); - } -} - - -/** - * Add the connection to the list of both neighbors. - * - * @param c Connection. - * - * @return #GNUNET_OK if everything went fine - * #GNUNET_SYSERR if the was an error and @c c is malformed. - */ -static int -register_neighbors (struct CadetConnection *c) -{ - struct CadetPeer *next_peer; - struct CadetPeer *prev_peer; - - next_peer = get_next_hop (c); - prev_peer = get_prev_hop (c); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "register neighbors for connection %s\n", - GMC_2s (c)); - path_debug (c->path); - LOG (GNUNET_ERROR_TYPE_DEBUG, "own pos %u\n", c->own_pos); - LOG (GNUNET_ERROR_TYPE_DEBUG, "putting connection %s to next peer %p\n", - GMC_2s (c), next_peer); - LOG (GNUNET_ERROR_TYPE_DEBUG, "next peer %p %s\n", next_peer, GMP_2s (next_peer)); - LOG (GNUNET_ERROR_TYPE_DEBUG, "putting connection %s to prev peer %p\n", - GMC_2s (c), prev_peer); - LOG (GNUNET_ERROR_TYPE_DEBUG, "prev peer %p %s\n", prev_peer, GMP_2s (prev_peer)); - - if (GNUNET_NO == GMP_is_neighbor (next_peer) - || GNUNET_NO == GMP_is_neighbor (prev_peer)) - { - if (GMC_is_origin (c, GNUNET_YES)) - GNUNET_STATISTICS_update (stats, "# local bad paths", 1, GNUNET_NO); - GNUNET_STATISTICS_update (stats, "# bad paths", 1, GNUNET_NO); - - LOG (GNUNET_ERROR_TYPE_DEBUG, " register neighbors failed\n"); - LOG (GNUNET_ERROR_TYPE_DEBUG, " prev: %s, neighbor?: %d\n", - GMP_2s (prev_peer), GMP_is_neighbor (prev_peer)); - LOG (GNUNET_ERROR_TYPE_DEBUG, " next: %s, neighbor?: %d\n", - GMP_2s (next_peer), GMP_is_neighbor (next_peer)); - return GNUNET_SYSERR; - } - - GMP_add_connection (next_peer, c); - GMP_add_connection (prev_peer, c); - - return GNUNET_OK; -} - - -/** - * Remove the connection from the list of both neighbors. - * - * @param c Connection. - */ -static void -unregister_neighbors (struct CadetConnection *c) -{ - struct CadetPeer *peer; - - peer = get_next_hop (c); - if (GNUNET_OK != GMP_remove_connection (peer, c)) - { - GNUNET_assert (CADET_CONNECTION_NEW == c->state - || CADET_CONNECTION_DESTROYED == c->state); - LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate: %u\n", c->state); - if (NULL != c->t) GMT_debug (c->t); - } - - peer = get_prev_hop (c); - if (GNUNET_OK != GMP_remove_connection (peer, c)) - { - GNUNET_assert (CADET_CONNECTION_NEW == c->state - || CADET_CONNECTION_DESTROYED == c->state); - LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate: %u\n", c->state); - if (NULL != c->t) GMT_debug (c->t); - } -} - - -/** - * Bind the connection to the peer and the tunnel to that peer. - * - * If the peer has no tunnel, create one. Update tunnel and connection - * data structres to reflect new status. - * - * @param c Connection. - * @param peer Peer. - */ -static void -add_to_peer (struct CadetConnection *c, struct CadetPeer *peer) -{ - GMP_add_tunnel (peer); - c->t = GMP_get_tunnel (peer); - GMT_add_connection (c->t, c); -} - - -/** - * Builds a path from a PeerIdentity array. - * - * @param peers PeerIdentity array. - * @param size Size of the @c peers array. - * @param own_pos Output parameter: own position in the path. - * - * @return Fixed and shortened path. - */ -static struct CadetPeerPath * -build_path_from_peer_ids (struct GNUNET_PeerIdentity *peers, - unsigned int size, - unsigned int *own_pos) -{ - struct CadetPeerPath *path; - GNUNET_PEER_Id shortid; - unsigned int i; - unsigned int j; - unsigned int offset; - - /* Create path */ - LOG (GNUNET_ERROR_TYPE_DEBUG, " Creating path...\n"); - path = path_new (size); - *own_pos = 0; - offset = 0; - for (i = 0; i < size; i++) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " - %u: taking %s\n", - i, GNUNET_i2s (&peers[i])); - shortid = GNUNET_PEER_intern (&peers[i]); - - /* Check for loops / duplicates */ - for (j = 0; j < i - offset; j++) - { - if (path->peers[j] == shortid) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " already exists at pos %u\n", j); - offset = i - j; - LOG (GNUNET_ERROR_TYPE_DEBUG, " offset now %u\n", offset); - GNUNET_PEER_change_rc (shortid, -1); - } - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " storing at %u\n", i - offset); - path->peers[i - offset] = shortid; - if (path->peers[i - offset] == myid) - *own_pos = i - offset; - } - path->length -= offset; - - if (path->peers[*own_pos] != myid) - { - /* create path: self not found in path through self */ - GNUNET_break_op (0); - path_destroy (path); - return NULL; - } - - return path; -} - - -/** - * Log receipt of message on stderr (INFO level). - * - * @param message Message received. - * @param peer Peer who sent the message. - * @param hash Connection ID. - */ -static void -log_message (const struct GNUNET_MessageHeader *message, - const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_CADET_Hash *hash) -{ - LOG (GNUNET_ERROR_TYPE_INFO, "<-- %s on connection %s from %s\n", - GM_m2s (ntohs (message->type)), GNUNET_h2s (GM_h2hc (hash)), - GNUNET_i2s (peer)); -} - -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ - -/** - * Core handler for connection creation. - * - * @param cls Closure (unused). - * @param peer Sender (neighbor). - * @param message Message. - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -int -GMC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_MessageHeader *message) -{ - struct GNUNET_CADET_ConnectionCreate *msg; - struct GNUNET_PeerIdentity *id; - struct GNUNET_CADET_Hash *cid; - struct CadetPeerPath *path; - struct CadetPeer *dest_peer; - struct CadetPeer *orig_peer; - struct CadetConnection *c; - unsigned int own_pos; - uint16_t size; - - /* Check size */ - size = ntohs (message->size); - if (size < sizeof (struct GNUNET_CADET_ConnectionCreate)) - { - GNUNET_break_op (0); - return GNUNET_OK; - } - - /* Calculate hops */ - size -= sizeof (struct GNUNET_CADET_ConnectionCreate); - if (size % sizeof (struct GNUNET_PeerIdentity)) - { - GNUNET_break_op (0); - return GNUNET_OK; - } - size /= sizeof (struct GNUNET_PeerIdentity); - if (1 > size) - { - GNUNET_break_op (0); - return GNUNET_OK; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " path has %u hops.\n", size); - - /* Get parameters */ - msg = (struct GNUNET_CADET_ConnectionCreate *) message; - cid = &msg->cid; - log_message (message, peer, cid); - id = (struct GNUNET_PeerIdentity *) &msg[1]; - LOG (GNUNET_ERROR_TYPE_DEBUG, " origin: %s\n", GNUNET_i2s (id)); - - /* Create connection */ - c = connection_get (cid); - if (NULL == c) - { - path = build_path_from_peer_ids ((struct GNUNET_PeerIdentity *) &msg[1], - size, &own_pos); - if (NULL == path) - return GNUNET_OK; - if (0 == own_pos) - { - GNUNET_break_op (0); - path_destroy (path); - return GNUNET_OK; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " Own position: %u\n", own_pos); - LOG (GNUNET_ERROR_TYPE_DEBUG, " Creating connection\n"); - c = GMC_new (cid, NULL, path_duplicate (path), own_pos); - if (NULL == c) - { - if (path->length - 1 == own_pos) - { - /* If we are destination, why did the creation fail? */ - GNUNET_break (0); - return GNUNET_OK; - } - send_broken_unknown (cid, &my_full_id, - GNUNET_PEER_resolve2 (path->peers[own_pos + 1]), - peer); - path_destroy (path); - return GNUNET_OK; - } - GMP_add_path_to_all (path, GNUNET_NO); - connection_reset_timeout (c, GNUNET_YES); - } - else - { - path = path_duplicate (c->path); - } - if (CADET_CONNECTION_NEW == c->state) - connection_change_state (c, CADET_CONNECTION_SENT); - - /* Remember peers */ - dest_peer = GMP_get (&id[size - 1]); - orig_peer = GMP_get (&id[0]); - - /* Is it a connection to us? */ - if (c->own_pos == path->length - 1) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " It's for us!\n"); - GMP_add_path_to_origin (orig_peer, path_duplicate (path), GNUNET_YES); - - add_to_peer (c, orig_peer); - if (CADET_TUNNEL3_NEW == GMT_get_cstate (c->t)) - GMT_change_cstate (c->t, CADET_TUNNEL3_WAITING); - - send_connection_ack (c, GNUNET_NO); - if (CADET_CONNECTION_SENT == c->state) - connection_change_state (c, CADET_CONNECTION_ACK); - } - else - { - /* It's for somebody else! Retransmit. */ - LOG (GNUNET_ERROR_TYPE_DEBUG, " Retransmitting.\n"); - GMP_add_path (dest_peer, path_duplicate (path), GNUNET_NO); - GMP_add_path_to_origin (orig_peer, path_duplicate (path), GNUNET_NO); - GMC_send_prebuilt_message (message, - GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, 0, - c, GNUNET_YES, GNUNET_YES, - NULL, NULL); - } - path_destroy (path); - return GNUNET_OK; -} - - -/** - * Core handler for path confirmations. - * - * @param cls closure - * @param message message - * @param peer peer identity this notification is about - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -int -GMC_handle_confirm (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_MessageHeader *message) -{ - struct GNUNET_CADET_ConnectionACK *msg; - struct CadetConnection *c; - struct CadetPeerPath *p; - struct CadetPeer *pi; - enum CadetConnectionState oldstate; - int fwd; - - msg = (struct GNUNET_CADET_ConnectionACK *) message; - log_message (message, peer, &msg->cid); - c = connection_get (&msg->cid); - if (NULL == c) - { - GNUNET_STATISTICS_update (stats, "# control on unknown connection", - 1, GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_DEBUG, " don't know the connection!\n"); - send_broken_unknown (&msg->cid, &my_full_id, NULL, peer); - return GNUNET_OK; - } - - if (GNUNET_NO != c->destroy) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " connection being destroyed\n"); - return GNUNET_OK; - } - - oldstate = c->state; - LOG (GNUNET_ERROR_TYPE_DEBUG, " via peer %s\n", GNUNET_i2s (peer)); - pi = GMP_get (peer); - if (get_next_hop (c) == pi) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " SYNACK\n"); - fwd = GNUNET_NO; - if (CADET_CONNECTION_SENT == oldstate) - connection_change_state (c, CADET_CONNECTION_ACK); - } - else if (get_prev_hop (c) == pi) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " ACK\n"); - fwd = GNUNET_YES; - connection_change_state (c, CADET_CONNECTION_READY); - } - else - { - GNUNET_break_op (0); - return GNUNET_OK; - } - - connection_reset_timeout (c, fwd); - - /* Add path to peers? */ - p = c->path; - if (NULL != p) - { - GMP_add_path_to_all (p, GNUNET_YES); - } - else - { - GNUNET_break (0); - } - - /* Message for us as creator? */ - if (GMC_is_origin (c, GNUNET_YES)) - { - if (GNUNET_NO != fwd) - { - GNUNET_break_op (0); - return GNUNET_OK; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " Connection (SYN)ACK for us!\n"); - - /* If just created, cancel the short timeout and start a long one */ - if (CADET_CONNECTION_SENT == oldstate) - connection_reset_timeout (c, GNUNET_YES); - - /* Change connection state */ - connection_change_state (c, CADET_CONNECTION_READY); - send_connection_ack (c, GNUNET_YES); - - /* Change tunnel state, trigger KX */ - if (CADET_TUNNEL3_WAITING == GMT_get_cstate (c->t)) - GMT_change_cstate (c->t, CADET_TUNNEL3_READY); - - return GNUNET_OK; - } - - /* Message for us as destination? */ - if (GMC_is_terminal (c, GNUNET_YES)) - { - if (GNUNET_YES != fwd) - { - GNUNET_break_op (0); - return GNUNET_OK; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " Connection ACK for us!\n"); - - /* If just created, cancel the short timeout and start a long one */ - if (CADET_CONNECTION_ACK == oldstate) - connection_reset_timeout (c, GNUNET_NO); - - /* Change tunnel state */ - if (CADET_TUNNEL3_WAITING == GMT_get_cstate (c->t)) - GMT_change_cstate (c->t, CADET_TUNNEL3_READY); - - return GNUNET_OK; - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n"); - GMC_send_prebuilt_message (message, - GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK, 0, - c, fwd, GNUNET_YES, NULL, NULL); - return GNUNET_OK; -} - - -/** - * Core handler for notifications of broken connections. - * - * @param cls Closure (unused). - * @param id Peer identity of sending neighbor. - * @param message Message. - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -int -GMC_handle_broken (void* cls, - const struct GNUNET_PeerIdentity* id, - const struct GNUNET_MessageHeader* message) -{ - struct GNUNET_CADET_ConnectionBroken *msg; - struct CadetConnection *c; - int fwd; - - msg = (struct GNUNET_CADET_ConnectionBroken *) message; - log_message (message, id, &msg->cid); - LOG (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n", - GNUNET_i2s (&msg->peer1)); - LOG (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n", - GNUNET_i2s (&msg->peer2)); - c = connection_get (&msg->cid); - if (NULL == c) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate CONNECTION_BROKEN\n"); - return GNUNET_OK; - } - - fwd = is_fwd (c, id); - if (GMC_is_terminal (c, fwd)) - { - struct GNUNET_MessageHeader *out_msg; - struct CadetPeer *neighbor; - struct CadetPeer *endpoint; - - neighbor = get_hop (c, !fwd); - endpoint = GMP_get_short (c->path->peers[c->path->length - 1]); - path_invalidate (c->path); - GMP_notify_broken_link (endpoint, &msg->peer1, &msg->peer2); - c->state = CADET_CONNECTION_DESTROYED; - while (NULL != (out_msg = GMP_connection_pop (neighbor, c))) - { - GNUNET_assert (NULL == - GMT_send_prebuilt_message (out_msg, c->t, NULL, GNUNET_YES, - NULL, NULL)); - } - - GMC_destroy (c); - } - else - { - GMC_send_prebuilt_message (message, - GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN, 0, - c, fwd, GNUNET_YES, NULL, NULL); - c->destroy = GNUNET_YES; - connection_cancel_queues (c, !fwd); - } - - return GNUNET_OK; - -} - - -/** - * Core handler for tunnel destruction - * - * @param cls Closure (unused). - * @param peer Peer identity of sending neighbor. - * @param message Message. - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -int -GMC_handle_destroy (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_MessageHeader *message) -{ - struct GNUNET_CADET_ConnectionDestroy *msg; - struct CadetConnection *c; - int fwd; - - msg = (struct GNUNET_CADET_ConnectionDestroy *) message; - log_message (message, peer, &msg->cid); - c = connection_get (&msg->cid); - if (NULL == c) - { - /* Probably already got the message from another path, - * destroyed the tunnel and retransmitted to children. - * Safe to ignore. - */ - GNUNET_STATISTICS_update (stats, "# control on unknown connection", - 1, GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_DEBUG, " connection unknown: already destroyed?\n"); - return GNUNET_OK; - } - fwd = is_fwd (c, peer); - if (GNUNET_SYSERR == fwd) - { - GNUNET_break_op (0); /* FIXME */ - return GNUNET_OK; - } - if (GNUNET_NO == GMC_is_terminal (c, fwd)) - GMC_send_prebuilt_message (message, - GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY, 0, - c, fwd, GNUNET_YES, NULL, NULL); - else if (0 == c->pending_messages) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " directly destroying connection!\n"); - GMC_destroy (c); - return GNUNET_OK; - } - c->destroy = GNUNET_YES; - c->state = CADET_CONNECTION_DESTROYED; - if (NULL != c->t) - { - GMT_remove_connection (c->t, c); - c->t = NULL; - } - - return GNUNET_OK; -} - -/** - * Generic handler for cadet network encrypted traffic. - * - * @param peer Peer identity this notification is about. - * @param msg Encrypted message. - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -static int -handle_cadet_encrypted (const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_CADET_Encrypted *msg) -{ - struct CadetConnection *c; - struct CadetPeer *neighbor; - struct CadetFlowControl *fc; - GNUNET_PEER_Id peer_id; - uint32_t pid; - uint32_t ttl; - size_t size; - int fwd; - - log_message (&msg->header, peer, &msg->cid); - - /* Check size */ - size = ntohs (msg->header.size); - if (size < - sizeof (struct GNUNET_CADET_Encrypted) + - sizeof (struct GNUNET_MessageHeader)) - { - GNUNET_break_op (0); - return GNUNET_OK; - } - - /* Check connection */ - c = connection_get (&msg->cid); - if (NULL == c) - { - GNUNET_STATISTICS_update (stats, "# unknown connection", 1, GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_DEBUG, "enc on unknown connection %s\n", - GNUNET_h2s (GM_h2hc (&msg->cid))); - send_broken_unknown (&msg->cid, &my_full_id, NULL, peer); - return GNUNET_OK; - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, " connection %s\n", GMC_2s (c)); - - /* Check if origin is as expected */ - neighbor = get_prev_hop (c); - peer_id = GNUNET_PEER_search (peer); - if (peer_id == GMP_get_short_id (neighbor)) - { - fwd = GNUNET_YES; - } - else - { - neighbor = get_next_hop (c); - if (peer_id == GMP_get_short_id (neighbor)) - { - fwd = GNUNET_NO; - } - else - { - /* Unexpected peer sending traffic on a connection. */ - GNUNET_break_op (0); - return GNUNET_OK; - } - } - - /* Check PID */ - fc = fwd ? &c->bck_fc : &c->fwd_fc; - pid = ntohl (msg->pid); - LOG (GNUNET_ERROR_TYPE_DEBUG, " PID %u (expected %u+)\n", - pid, fc->last_pid_recv + 1); - if (GM_is_pid_bigger (pid, fc->last_ack_sent)) - { - GNUNET_STATISTICS_update (stats, "# unsolicited message", 1, GNUNET_NO); - GNUNET_break_op (0); - LOG (GNUNET_ERROR_TYPE_WARNING, - "Received PID %u, (prev %u), ACK %u\n", - pid, fc->last_pid_recv, fc->last_ack_sent); - return GNUNET_OK; - } - if (GNUNET_NO == GM_is_pid_bigger (pid, fc->last_pid_recv)) - { - GNUNET_STATISTICS_update (stats, "# duplicate PID", 1, GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_DEBUG, - " PID %u not expected (%u+), dropping!\n", - pid, fc->last_pid_recv + 1); - return GNUNET_OK; - } - if (CADET_CONNECTION_SENT == c->state || CADET_CONNECTION_ACK == c->state) - connection_change_state (c, CADET_CONNECTION_READY); - connection_reset_timeout (c, fwd); - fc->last_pid_recv = pid; - - /* Is this message for us? */ - if (GMC_is_terminal (c, fwd)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " message for us!\n"); - GNUNET_STATISTICS_update (stats, "# messages received", 1, GNUNET_NO); - - if (NULL == c->t) - { - GNUNET_break (GNUNET_NO != c->destroy); - return GNUNET_OK; - } - fc->last_pid_recv = pid; - GMT_handle_encrypted (c->t, msg); - GMC_send_ack (c, fwd, GNUNET_NO); - return GNUNET_OK; - } - - /* Message not for us: forward to next hop */ - LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n"); - ttl = ntohl (msg->ttl); - LOG (GNUNET_ERROR_TYPE_DEBUG, " ttl: %u\n", ttl); - if (ttl == 0) - { - GNUNET_STATISTICS_update (stats, "# TTL drops", 1, GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_WARNING, " TTL is 0, DROPPING!\n"); - GMC_send_ack (c, fwd, GNUNET_NO); - return GNUNET_OK; - } - - GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO); - GMC_send_prebuilt_message (&msg->header, - GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED, 0, - c, fwd, GNUNET_NO, NULL, NULL); - - return GNUNET_OK; -} - -/** - * Generic handler for cadet network encrypted traffic. - * - * @param peer Peer identity this notification is about. - * @param msg Encrypted message. - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -static int -handle_cadet_kx (const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_CADET_KX *msg) -{ - struct CadetConnection *c; - struct CadetPeer *neighbor; - GNUNET_PEER_Id peer_id; - size_t size; - int fwd; - - log_message (&msg->header, peer, &msg->cid); - - /* Check size */ - size = ntohs (msg->header.size); - if (size < - sizeof (struct GNUNET_CADET_KX) + - sizeof (struct GNUNET_MessageHeader)) - { - GNUNET_break_op (0); - return GNUNET_OK; - } - - /* Check connection */ - c = connection_get (&msg->cid); - if (NULL == c) - { - GNUNET_STATISTICS_update (stats, "# unknown connection", 1, GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_DEBUG, "kx on unknown connection %s\n", - GNUNET_h2s (GM_h2hc (&msg->cid))); - send_broken_unknown (&msg->cid, &my_full_id, NULL, peer); - return GNUNET_OK; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " on connection %s\n", GMC_2s (c)); - - /* Check if origin is as expected */ - neighbor = get_prev_hop (c); - peer_id = GNUNET_PEER_search (peer); - if (peer_id == GMP_get_short_id (neighbor)) - { - fwd = GNUNET_YES; - } - else - { - neighbor = get_next_hop (c); - if (peer_id == GMP_get_short_id (neighbor)) - { - fwd = GNUNET_NO; - } - else - { - /* Unexpected peer sending traffic on a connection. */ - GNUNET_break_op (0); - return GNUNET_OK; - } - } - - /* Count as connection confirmation. */ - if (CADET_CONNECTION_SENT == c->state || CADET_CONNECTION_ACK == c->state) - { - connection_change_state (c, CADET_CONNECTION_READY); - if (NULL != c->t) - { - if (CADET_TUNNEL3_WAITING == GMT_get_cstate (c->t)) - GMT_change_cstate (c->t, CADET_TUNNEL3_READY); - } - } - connection_reset_timeout (c, fwd); - - /* Is this message for us? */ - if (GMC_is_terminal (c, fwd)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " message for us!\n"); - GNUNET_STATISTICS_update (stats, "# messages received", 1, GNUNET_NO); - if (NULL == c->t) - { - GNUNET_break (0); - return GNUNET_OK; - } - GMT_handle_kx (c->t, &msg[1].header); - return GNUNET_OK; - } - - /* Message not for us: forward to next hop */ - LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n"); - GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO); - GMC_send_prebuilt_message (&msg->header, GNUNET_MESSAGE_TYPE_CADET_KX, 0, - c, fwd, GNUNET_NO, NULL, NULL); - - return GNUNET_OK; -} - - -/** - * Core handler for encrypted cadet network traffic (channel mgmt, data). - * - * @param cls Closure (unused). - * @param message Message received. - * @param peer Peer who sent the message. - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -int -GMC_handle_encrypted (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_MessageHeader *message) -{ - return handle_cadet_encrypted (peer, - (struct GNUNET_CADET_Encrypted *)message); -} - - -/** - * Core handler for key exchange traffic (ephemeral key, ping, pong). - * - * @param cls Closure (unused). - * @param message Message received. - * @param peer Peer who sent the message. - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -int -GMC_handle_kx (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_MessageHeader *message) -{ - return handle_cadet_kx (peer, - (struct GNUNET_CADET_KX *) message); -} - - -/** - * Core handler for cadet network traffic point-to-point acks. - * - * @param cls closure - * @param message message - * @param peer peer identity this notification is about - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -int -GMC_handle_ack (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_MessageHeader *message) -{ - struct GNUNET_CADET_ACK *msg; - struct CadetConnection *c; - struct CadetFlowControl *fc; - GNUNET_PEER_Id id; - uint32_t ack; - int fwd; - - msg = (struct GNUNET_CADET_ACK *) message; - log_message (message, peer, &msg->cid); - c = connection_get (&msg->cid); - if (NULL == c) - { - GNUNET_STATISTICS_update (stats, "# ack on unknown connection", 1, - GNUNET_NO); - send_broken_unknown (&msg->cid, &my_full_id, NULL, peer); - return GNUNET_OK; - } - - /* Is this a forward or backward ACK? */ - id = GNUNET_PEER_search (peer); - if (GMP_get_short_id (get_next_hop (c)) == id) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD ACK\n"); - fc = &c->fwd_fc; - fwd = GNUNET_YES; - } - else if (GMP_get_short_id (get_prev_hop (c)) == id) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK ACK\n"); - fc = &c->bck_fc; - fwd = GNUNET_NO; - } - else - { - GNUNET_break_op (0); - return GNUNET_OK; - } - - ack = ntohl (msg->ack); - LOG (GNUNET_ERROR_TYPE_DEBUG, " ACK %u (was %u)\n", - ack, fc->last_ack_recv); - if (GM_is_pid_bigger (ack, fc->last_ack_recv)) - fc->last_ack_recv = ack; - - /* Cancel polling if the ACK is big enough. */ - if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task && - GM_is_pid_bigger (fc->last_ack_recv, fc->last_pid_sent)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " Cancel poll\n"); - GNUNET_SCHEDULER_cancel (fc->poll_task); - fc->poll_task = GNUNET_SCHEDULER_NO_TASK; - fc->poll_time = GNUNET_TIME_UNIT_SECONDS; - } - - connection_unlock_queue (c, fwd); - - return GNUNET_OK; -} - - -/** - * Core handler for cadet network traffic point-to-point ack polls. - * - * @param cls closure - * @param message message - * @param peer peer identity this notification is about - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -int -GMC_handle_poll (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_MessageHeader *message) -{ - struct GNUNET_CADET_Poll *msg; - struct CadetConnection *c; - struct CadetFlowControl *fc; - GNUNET_PEER_Id id; - uint32_t pid; - int fwd; - - msg = (struct GNUNET_CADET_Poll *) message; - log_message (message, peer, &msg->cid); - c = connection_get (&msg->cid); - if (NULL == c) - { - GNUNET_STATISTICS_update (stats, "# poll on unknown connection", 1, - GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL message on unknown connection %s!\n", - GNUNET_h2s (GM_h2hc (&msg->cid))); - send_broken_unknown (&msg->cid, &my_full_id, NULL, peer); - return GNUNET_OK; - } - - /* Is this a forward or backward ACK? - * Note: a poll should never be needed in a loopback case, - * since there is no possiblility of packet loss there, so - * this way of discerining FWD/BCK should not be a problem. - */ - id = GNUNET_PEER_search (peer); - if (GMP_get_short_id (get_next_hop (c)) == id) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD FC\n"); - fc = &c->fwd_fc; - } - else if (GMP_get_short_id (get_prev_hop (c)) == id) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK FC\n"); - fc = &c->bck_fc; - } - else - { - GNUNET_break_op (0); - return GNUNET_OK; - } - - pid = ntohl (msg->pid); - LOG (GNUNET_ERROR_TYPE_DEBUG, " PID %u, OLD %u\n", pid, fc->last_pid_recv); - fc->last_pid_recv = pid; - fwd = fc == &c->bck_fc; - GMC_send_ack (c, fwd, GNUNET_YES); - - return GNUNET_OK; -} - - -/** - * Send an ACK on the appropriate connection/channel, depending on - * the direction and the position of the peer. - * - * @param c Which connection to send the hop-by-hop ACK. - * @param fwd Is this a fwd ACK? (will go dest->root). - * @param force Send the ACK even if suboptimal (e.g. requested by POLL). - */ -void -GMC_send_ack (struct CadetConnection *c, int fwd, int force) -{ - unsigned int buffer; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "GMC send %s ACK on %s\n", - GM_f2s (fwd), GMC_2s (c)); - - if (NULL == c) - { - GNUNET_break (0); - return; - } - - if (GNUNET_NO != c->destroy) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " being destroyed, why bother...\n"); - return; - } - - /* Get available buffer space */ - if (GMC_is_terminal (c, fwd)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " getting from all channels\n"); - buffer = GMT_get_channels_buffer (c->t); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " getting from one connection\n"); - buffer = GMC_get_buffer (c, fwd); - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer available: %u\n", buffer); - if (0 == buffer && GNUNET_NO == force) - return; - - /* Send available buffer space */ - if (GMC_is_origin (c, fwd)) - { - GNUNET_assert (NULL != c->t); - LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channels...\n"); - GMT_unchoke_channels (c->t); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on connection\n"); - send_ack (c, buffer, fwd, force); - } -} - - -/** - * Initialize the connections subsystem - * - * @param c Configuration handle. - */ -void -GMC_init (const struct GNUNET_CONFIGURATION_Handle *c) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_MSGS_QUEUE", - &max_msgs_queue)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "CADET", "MAX_MSGS_QUEUE", "MISSING"); - GNUNET_SCHEDULER_shutdown (); - return; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_CONNECTIONS", - &max_connections)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "CADET", "MAX_CONNECTIONS", "MISSING"); - GNUNET_SCHEDULER_shutdown (); - return; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (c, "CADET", "REFRESH_CONNECTION_TIME", - &refresh_connection_time)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "CADET", "REFRESH_CONNECTION_TIME", "MISSING"); - GNUNET_SCHEDULER_shutdown (); - return; - } - create_connection_time = GNUNET_TIME_UNIT_SECONDS; - connections = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_NO); -} - - -/** - * Destroy each connection on shutdown. - * - * @param cls Closure (unused). - * @param key Current key code (CID, unused). - * @param value Value in the hash map (connection) - * - * @return #GNUNET_YES, because we should continue to iterate, - */ -static int -shutdown_iterator (void *cls, - const struct GNUNET_HashCode *key, - void *value) -{ - struct CadetConnection *c = value; - - GMC_destroy (c); - return GNUNET_YES; -} - - -/** - * Shut down the connections subsystem. - */ -void -GMC_shutdown (void) -{ - GNUNET_CONTAINER_multihashmap_iterate (connections, &shutdown_iterator, NULL); - GNUNET_CONTAINER_multihashmap_destroy (connections); - connections = NULL; -} - - -struct CadetConnection * -GMC_new (const struct GNUNET_CADET_Hash *cid, - struct CadetTunnel3 *t, - struct CadetPeerPath *p, - unsigned int own_pos) -{ - struct CadetConnection *c; - - c = GNUNET_new (struct CadetConnection); - c->id = *cid; - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_put (connections, - GMC_get_h (c), c, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); - fc_init (&c->fwd_fc); - fc_init (&c->bck_fc); - c->fwd_fc.c = c; - c->bck_fc.c = c; - - c->t = t; - GNUNET_assert (own_pos <= p->length - 1); - c->own_pos = own_pos; - c->path = p; - p->c = c; - - if (GNUNET_OK != register_neighbors (c)) - { - if (0 == own_pos) - { - path_invalidate (c->path); - c->t = NULL; - c->path = NULL; - } - GMC_destroy (c); - return NULL; - } - - return c; -} - - -void -GMC_destroy (struct CadetConnection *c) -{ - if (NULL == c) - { - GNUNET_break (0); - return; - } - - if (2 == c->destroy) /* cancel queues -> GMP_queue_cancel -> q_destroy -> */ - return; /* -> message_sent -> GMC_destroy. Don't loop. */ - c->destroy = 2; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying connection %s\n", GMC_2s (c)); - LOG (GNUNET_ERROR_TYPE_DEBUG, " fc's f: %p, b: %p\n", - &c->fwd_fc, &c->bck_fc); - LOG (GNUNET_ERROR_TYPE_DEBUG, " fc tasks f: %u, b: %u\n", - c->fwd_fc.poll_task, c->bck_fc.poll_task); - - /* Cancel all traffic */ - if (NULL != c->path) - { - connection_cancel_queues (c, GNUNET_YES); - connection_cancel_queues (c, GNUNET_NO); - unregister_neighbors (c); - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, " fc tasks f: %u, b: %u\n", - c->fwd_fc.poll_task, c->bck_fc.poll_task); - - /* Cancel maintainance task (keepalive/timeout) */ - if (NULL != c->fwd_fc.poll_msg) - { - GMC_cancel (c->fwd_fc.poll_msg); - LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL msg FWD canceled\n"); - } - if (NULL != c->bck_fc.poll_msg) - { - GMC_cancel (c->bck_fc.poll_msg); - LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL msg BCK canceled\n"); - } - - /* Delete from tunnel */ - if (NULL != c->t) - GMT_remove_connection (c->t, c); - - if (GNUNET_NO == GMC_is_origin (c, GNUNET_YES) && NULL != c->path) - path_destroy (c->path); - if (GNUNET_SCHEDULER_NO_TASK != c->fwd_maintenance_task) - GNUNET_SCHEDULER_cancel (c->fwd_maintenance_task); - if (GNUNET_SCHEDULER_NO_TASK != c->bck_maintenance_task) - GNUNET_SCHEDULER_cancel (c->bck_maintenance_task); - if (GNUNET_SCHEDULER_NO_TASK != c->fwd_fc.poll_task) - { - GNUNET_SCHEDULER_cancel (c->fwd_fc.poll_task); - LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL FWD canceled\n"); - } - if (GNUNET_SCHEDULER_NO_TASK != c->bck_fc.poll_task) - { - GNUNET_SCHEDULER_cancel (c->bck_fc.poll_task); - LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL BCK canceled\n"); - } - - GNUNET_break (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_remove (connections, - GMC_get_h (c), c)); - - GNUNET_STATISTICS_update (stats, "# connections", -1, GNUNET_NO); - GNUNET_free (c); -} - -/** - * Get the connection ID. - * - * @param c Connection to get the ID from. - * - * @return ID of the connection. - */ -const struct GNUNET_CADET_Hash * -GMC_get_id (const struct CadetConnection *c) -{ - return &c->id; -} - - -/** - * Get the connection ID. - * - * @param c Connection to get the ID from. - * - * @return ID of the connection. - */ -const struct GNUNET_HashCode * -GMC_get_h (const struct CadetConnection *c) -{ - return GM_h2hc (&c->id); -} - - -/** - * Get the connection path. - * - * @param c Connection to get the path from. - * - * @return path used by the connection. - */ -const struct CadetPeerPath * -GMC_get_path (const struct CadetConnection *c) -{ - if (GNUNET_NO == c->destroy) - return c->path; - return NULL; -} - - -/** - * Get the connection state. - * - * @param c Connection to get the state from. - * - * @return state of the connection. - */ -enum CadetConnectionState -GMC_get_state (const struct CadetConnection *c) -{ - return c->state; -} - -/** - * Get the connection tunnel. - * - * @param c Connection to get the tunnel from. - * - * @return tunnel of the connection. - */ -struct CadetTunnel3 * -GMC_get_tunnel (const struct CadetConnection *c) -{ - return c->t; -} - - -/** - * Get free buffer space in a connection. - * - * @param c Connection. - * @param fwd Is query about FWD traffic? - * - * @return Free buffer space [0 - max_msgs_queue/max_connections] - */ -unsigned int -GMC_get_buffer (struct CadetConnection *c, int fwd) -{ - struct CadetFlowControl *fc; - - fc = fwd ? &c->fwd_fc : &c->bck_fc; - - return (fc->queue_max - fc->queue_n); -} - -/** - * Get how many messages have we allowed to send to us from a direction. - * - * @param c Connection. - * @param fwd Are we asking about traffic from FWD (BCK messages)? - * - * @return last_ack_sent - last_pid_recv - */ -unsigned int -GMC_get_allowed (struct CadetConnection *c, int fwd) -{ - struct CadetFlowControl *fc; - - fc = fwd ? &c->fwd_fc : &c->bck_fc; - if (GM_is_pid_bigger(fc->last_pid_recv, fc->last_ack_sent)) - { - return 0; - } - return (fc->last_ack_sent - fc->last_pid_recv); -} - -/** - * Get messages queued in a connection. - * - * @param c Connection. - * @param fwd Is query about FWD traffic? - * - * @return Number of messages queued. - */ -unsigned int -GMC_get_qn (struct CadetConnection *c, int fwd) -{ - struct CadetFlowControl *fc; - - fc = fwd ? &c->fwd_fc : &c->bck_fc; - - return fc->queue_n; -} - - -/** - * Get next PID to use. - * - * @param c Connection. - * @param fwd Is query about FWD traffic? - * - * @return Last PID used + 1. - */ -unsigned int -GMC_get_pid (struct CadetConnection *c, int fwd) -{ - struct CadetFlowControl *fc; - - fc = fwd ? &c->fwd_fc : &c->bck_fc; - - return fc->last_pid_sent + 1; -} - - -/** - * Allow the connection to advertise a buffer of the given size. - * - * The connection will send an @c fwd ACK message (so: in direction !fwd) - * allowing up to last_pid_recv + buffer. - * - * @param c Connection. - * @param buffer How many more messages the connection can accept. - * @param fwd Is this about FWD traffic? (The ack will go dest->root). - */ -void -GMC_allow (struct CadetConnection *c, unsigned int buffer, int fwd) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, " allowing %s %u messages %s\n", - GMC_2s (c), buffer, GM_f2s (fwd)); - send_ack (c, buffer, fwd, GNUNET_NO); -} - - -/** - * Notify other peers on a connection of a broken link. Mark connections - * to destroy after all traffic has been sent. - * - * @param c Connection on which there has been a disconnection. - * @param peer Peer that disconnected. - */ -void -GMC_notify_broken (struct CadetConnection *c, - struct CadetPeer *peer) -{ - int fwd; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - " notify broken on %s due to %s disconnect\n", - GMC_2s (c), GMP_2s (peer)); - - fwd = peer == get_prev_hop (c); - - if (GNUNET_YES == GMC_is_terminal (c, fwd)) - { - /* Local shutdown, no one to notify about this. */ - GMC_destroy (c); - return; - } - if (GNUNET_NO == c->destroy) - send_broken (c, &my_full_id, GMP_get_id (peer), fwd); - - /* Connection will have at least one pending message - * (the one we just scheduled), so no point in checking whether to - * destroy immediately. */ - c->destroy = GNUNET_YES; - c->state = CADET_CONNECTION_DESTROYED; - - /** - * Cancel all queues, if no message is left, connection will be destroyed. - */ - connection_cancel_queues (c, !fwd); - - return; -} - - -/** - * Is this peer the first one on the connection? - * - * @param c Connection. - * @param fwd Is this about fwd traffic? - * - * @return #GNUNET_YES if origin, #GNUNET_NO if relay/terminal. - */ -int -GMC_is_origin (struct CadetConnection *c, int fwd) -{ - if (!fwd && c->path->length - 1 == c->own_pos ) - return GNUNET_YES; - if (fwd && 0 == c->own_pos) - return GNUNET_YES; - return GNUNET_NO; -} - - -/** - * Is this peer the last one on the connection? - * - * @param c Connection. - * @param fwd Is this about fwd traffic? - * Note that the ROOT is the terminal for BCK traffic! - * - * @return #GNUNET_YES if terminal, #GNUNET_NO if relay/origin. - */ -int -GMC_is_terminal (struct CadetConnection *c, int fwd) -{ - return GMC_is_origin (c, !fwd); -} - - -/** - * See if we are allowed to send by the next hop in the given direction. - * - * @param c Connection. - * @param fwd Is this about fwd traffic? - * - * @return #GNUNET_YES in case it's OK to send. - */ -int -GMC_is_sendable (struct CadetConnection *c, int fwd) -{ - struct CadetFlowControl *fc; - - LOG (GNUNET_ERROR_TYPE_DEBUG, " checking sendability of %s traffic on %s\n", - GM_f2s (fwd), GMC_2s (c)); - if (NULL == c) - { - GNUNET_break (0); - return GNUNET_YES; - } - fc = fwd ? &c->fwd_fc : &c->bck_fc; - LOG (GNUNET_ERROR_TYPE_DEBUG, - " last ack recv: %u, last pid sent: %u\n", - fc->last_ack_recv, fc->last_pid_sent); - if (GM_is_pid_bigger (fc->last_ack_recv, fc->last_pid_sent)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " sendable\n"); - return GNUNET_YES; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " not sendable\n"); - return GNUNET_NO; -} - - -/** - * Check if this connection is a direct one (never trim a direct connection). - * - * @param c Connection. - * - * @return #GNUNET_YES in case it's a direct connection, #GNUNET_NO otherwise. - */ -int -GMC_is_direct (struct CadetConnection *c) -{ - return (c->path->length == 2) ? GNUNET_YES : GNUNET_NO; -} - -/** - * Sends an already built message on a connection, properly registering - * all used resources. - * - * @param message Message to send. Function makes a copy of it. - * If message is not hop-by-hop, decrements TTL of copy. - * @param payload_type Type of payload, in case the message is encrypted. - * @param c Connection on which this message is transmitted. - * @param fwd Is this a fwd message? - * @param force Force the connection to accept the message (buffer overfill). - * @param cont Continuation called once message is sent. Can be NULL. - * @param cont_cls Closure for @c cont. - * - * @return Handle to cancel the message before it's sent. - * NULL on error or if @c cont is NULL. - * Invalid on @c cont call. - */ -struct CadetConnectionQueue * -GMC_send_prebuilt_message (const struct GNUNET_MessageHeader *message, - uint16_t payload_type, uint32_t payload_id, - struct CadetConnection *c, int fwd, int force, - GMC_sent cont, void *cont_cls) -{ - struct CadetFlowControl *fc; - struct CadetConnectionQueue *q; - void *data; - size_t size; - uint16_t type; - int droppable; - - size = ntohs (message->size); - data = GNUNET_malloc (size); - memcpy (data, message, size); - type = ntohs (message->type); - LOG (GNUNET_ERROR_TYPE_INFO, "--> %s (%s %u) on connection %s (%u bytes)\n", - GM_m2s (type), GM_m2s (payload_type), payload_id, GMC_2s (c), size); - - fc = fwd ? &c->fwd_fc : &c->bck_fc; - droppable = GNUNET_NO == force; - switch (type) - { - struct GNUNET_CADET_Encrypted *emsg; - struct GNUNET_CADET_KX *kmsg; - struct GNUNET_CADET_ACK *amsg; - struct GNUNET_CADET_Poll *pmsg; - struct GNUNET_CADET_ConnectionDestroy *dmsg; - struct GNUNET_CADET_ConnectionBroken *bmsg; - uint32_t ttl; - - case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED: - emsg = (struct GNUNET_CADET_Encrypted *) data; - ttl = ntohl (emsg->ttl); - if (0 == ttl) - { - GNUNET_break_op (0); - GNUNET_free (data); - return NULL; - } - emsg->cid = c->id; - emsg->ttl = htonl (ttl - 1); - emsg->pid = htonl (0); - LOG (GNUNET_ERROR_TYPE_DEBUG, " Q_N+ %p %u\n", fc, fc->queue_n); - LOG (GNUNET_ERROR_TYPE_DEBUG, "last pid sent %u\n", fc->last_pid_sent); - LOG (GNUNET_ERROR_TYPE_DEBUG, " ack recv %u\n", fc->last_ack_recv); - if (GNUNET_YES == droppable) - { - fc->queue_n++; - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " not droppable, Q_N stays the same\n"); - } - if (GM_is_pid_bigger (fc->last_pid_sent + 1, fc->last_ack_recv)) - { - GMC_start_poll (c, fwd); - } - break; - - case GNUNET_MESSAGE_TYPE_CADET_KX: - kmsg = (struct GNUNET_CADET_KX *) data; - kmsg->cid = c->id; - break; - - case GNUNET_MESSAGE_TYPE_CADET_ACK: - amsg = (struct GNUNET_CADET_ACK *) data; - amsg->cid = c->id; - LOG (GNUNET_ERROR_TYPE_DEBUG, " ack %u\n", ntohl (amsg->ack)); - droppable = GNUNET_NO; - break; - - case GNUNET_MESSAGE_TYPE_CADET_POLL: - pmsg = (struct GNUNET_CADET_Poll *) data; - pmsg->cid = c->id; - LOG (GNUNET_ERROR_TYPE_DEBUG, " poll %u\n", ntohl (pmsg->pid)); - droppable = GNUNET_NO; - break; - - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY: - dmsg = (struct GNUNET_CADET_ConnectionDestroy *) data; - dmsg->cid = c->id; - break; - - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN: - bmsg = (struct GNUNET_CADET_ConnectionBroken *) data; - bmsg->cid = c->id; - break; - - case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE: - GNUNET_break (0); - /* falltrough */ - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE: - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK: - break; - - default: - GNUNET_break (0); - GNUNET_free (data); - return NULL; - } - - if (fc->queue_n > fc->queue_max && droppable) - { - GNUNET_STATISTICS_update (stats, "# messages dropped (buffer full)", - 1, GNUNET_NO); - GNUNET_break (0); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "queue full: %u/%u\n", - fc->queue_n, fc->queue_max); - if (GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED == type) - { - fc->queue_n--; - } - GNUNET_free (data); - return NULL; /* Drop this message */ - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %p %u\n", c, c->pending_messages); -// c->pending_messages++; - - q = GNUNET_new (struct CadetConnectionQueue); - q->forced = !droppable; - q->q = GMP_queue_add (get_hop (c, fwd), data, type, payload_type, payload_id, - size, c, fwd, &conn_message_sent, q); - if (NULL == q->q) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING dropping msg on %s\n", GMC_2s (c)); - GNUNET_free (data); - GNUNET_free (q); - return NULL; - } - q->cont = cont; - q->cont_cls = cont_cls; - return (NULL == cont) ? NULL : q; -} - - -/** - * Cancel a previously sent message while it's in the queue. - * - * ONLY can be called before the continuation given to the send function - * is called. Once the continuation is called, the message is no longer in the - * queue. - * - * @param q Handle to the queue. - */ -void -GMC_cancel (struct CadetConnectionQueue *q) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "! GMC cancel message\n"); - - /* queue destroy calls message_sent, which calls q->cont and frees q */ - GMP_queue_destroy (q->q, GNUNET_YES, GNUNET_NO, 0); -} - - -/** - * Sends a CREATE CONNECTION message for a path to a peer. - * Changes the connection and tunnel states if necessary. - * - * @param connection Connection to create. - */ -void -GMC_send_create (struct CadetConnection *connection) -{ - enum CadetTunnel3CState state; - size_t size; - - size = sizeof (struct GNUNET_CADET_ConnectionCreate); - size += connection->path->length * sizeof (struct GNUNET_PeerIdentity); - - LOG (GNUNET_ERROR_TYPE_INFO, "===> %s on connection %s (%u bytes)\n", - GM_m2s (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE), - GMC_2s (connection), size); - LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %p %u (create)\n", - connection, connection->pending_messages); - connection->pending_messages++; - - connection->maintenance_q = - GMP_queue_add (get_next_hop (connection), NULL, - GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, - GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, 0, - size, connection, GNUNET_YES, &conn_message_sent, NULL); - - state = GMT_get_cstate (connection->t); - if (CADET_TUNNEL3_SEARCHING == state || CADET_TUNNEL3_NEW == state) - GMT_change_cstate (connection->t, CADET_TUNNEL3_WAITING); - if (CADET_CONNECTION_NEW == connection->state) - connection_change_state (connection, CADET_CONNECTION_SENT); -} - - -/** - * Send a message to all peers in this connection that the connection - * is no longer valid. - * - * If some peer should not receive the message, it should be zero'ed out - * before calling this function. - * - * @param c The connection whose peers to notify. - */ -void -GMC_send_destroy (struct CadetConnection *c) -{ - struct GNUNET_CADET_ConnectionDestroy msg; - - if (GNUNET_YES == c->destroy) - return; - - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);; - msg.cid = c->id; - LOG (GNUNET_ERROR_TYPE_DEBUG, - " sending connection destroy for connection %s\n", - GMC_2s (c)); - - if (GNUNET_NO == GMC_is_terminal (c, GNUNET_YES)) - GMC_send_prebuilt_message (&msg.header, - GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY, 0, - c, GNUNET_YES, GNUNET_YES, NULL, NULL); - if (GNUNET_NO == GMC_is_terminal (c, GNUNET_NO)) - GMC_send_prebuilt_message (&msg.header, - GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY, 0, - c, GNUNET_NO, GNUNET_YES, NULL, NULL); - c->destroy = GNUNET_YES; - c->state = CADET_CONNECTION_DESTROYED; -} - - -/** - * @brief Start a polling timer for the connection. - * - * When a neighbor does not accept more traffic on the connection it could be - * caused by a simple congestion or by a lost ACK. Polling enables to check - * for the lastest ACK status for a connection. - * - * @param c Connection. - * @param fwd Should we poll in the FWD direction? - */ -void -GMC_start_poll (struct CadetConnection *c, int fwd) -{ - struct CadetFlowControl *fc; - - fc = fwd ? &c->fwd_fc : &c->bck_fc; - LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL %s requested\n", - GM_f2s (fwd)); - if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task || NULL != fc->poll_msg) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " *** not needed (%u, %p)\n", - fc->poll_task, fc->poll_msg); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL started on request\n"); - fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time, - &connection_poll, - fc); -} - - -/** - * @brief Stop polling a connection for ACKs. - * - * Once we have enough ACKs for future traffic, polls are no longer necessary. - * - * @param c Connection. - * @param fwd Should we stop the poll in the FWD direction? - */ -void -GMC_stop_poll (struct CadetConnection *c, int fwd) -{ - struct CadetFlowControl *fc; - - fc = fwd ? &c->fwd_fc : &c->bck_fc; - if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task) - { - GNUNET_SCHEDULER_cancel (fc->poll_task); - fc->poll_task = GNUNET_SCHEDULER_NO_TASK; - } -} - -/** - * Get a (static) string for a connection. - * - * @param c Connection. - */ -const char * -GMC_2s (const struct CadetConnection *c) -{ - if (NULL == c) - return "NULL"; - - if (NULL != c->t) - { - static char buf[128]; - - sprintf (buf, "%s (->%s)", - GNUNET_h2s (GM_h2hc (GMC_get_id (c))), GMT_2s (c->t)); - return buf; - } - return GNUNET_h2s (GM_h2hc (&c->id)); -} diff --git a/src/mesh/gnunet-service-cadet_connection.h b/src/mesh/gnunet-service-cadet_connection.h deleted file mode 100644 index 4e1104c2b..000000000 --- a/src/mesh/gnunet-service-cadet_connection.h +++ /dev/null @@ -1,566 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2013 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 cadet/gnunet-service-cadet_connection.h - * @brief cadet service; dealing with connections - * @author Bartlomiej Polot - * - * All functions in this file should use the prefix GMC (Gnunet Cadet Connection) - */ - -#ifndef GNUNET_SERVICE_CADET_CONNECTION_H -#define GNUNET_SERVICE_CADET_CONNECTION_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "gnunet_util_lib.h" - - -/** - * All the states a connection can be in. - */ -enum CadetConnectionState -{ - /** - * Uninitialized status, should never appear in operation. - */ - CADET_CONNECTION_NEW, - - /** - * Connection create message sent, waiting for ACK. - */ - CADET_CONNECTION_SENT, - - /** - * Connection ACK sent, waiting for ACK. - */ - CADET_CONNECTION_ACK, - - /** - * Connection confirmed, ready to carry traffic. - */ - CADET_CONNECTION_READY, - - /** - * Connection to be destroyed, just waiting to empty queues. - */ - CADET_CONNECTION_DESTROYED, -}; - - -/** - * Struct containing all information regarding a connection to a peer. - */ -struct CadetConnection; - -/** - * Handle for messages queued but not yet sent. - */ -struct CadetConnectionQueue; - -#include "cadet_path.h" -#include "gnunet-service-cadet_channel.h" -#include "gnunet-service-cadet_peer.h" - - - -/** - * Callback called when a queued message is sent. - * - * @param cls Closure. - * @param c Connection this message was on. - * @param type Type of message sent. - * @param fwd Was this a FWD going message? - * @param size Size of the message. - */ -typedef void (*GMC_sent) (void *cls, - struct CadetConnection *c, - struct CadetConnectionQueue *q, - uint16_t type, int fwd, size_t size); - -/** - * Core handler for connection creation. - * - * @param cls Closure (unused). - * @param peer Sender (neighbor). - * @param message Message. - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -int -GMC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_MessageHeader *message); - -/** - * Core handler for path confirmations. - * - * @param cls closure - * @param message message - * @param peer peer identity this notification is about - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -int -GMC_handle_confirm (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_MessageHeader *message); - -/** - * Core handler for notifications of broken paths - * - * @param cls Closure (unused). - * @param id Peer identity of sending neighbor. - * @param message Message. - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -int -GMC_handle_broken (void* cls, - const struct GNUNET_PeerIdentity* id, - const struct GNUNET_MessageHeader* message); - -/** - * Core handler for tunnel destruction - * - * @param cls Closure (unused). - * @param peer Peer identity of sending neighbor. - * @param message Message. - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -int -GMC_handle_destroy (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_MessageHeader *message); - -/** - * Core handler for encrypted cadet network traffic (channel mgmt, data). - * - * @param cls Closure (unused). - * @param message Message received. - * @param peer Peer who sent the message. - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -int -GMC_handle_encrypted (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_MessageHeader *message); - -/** - * Core handler for key exchange traffic (ephemeral key, ping, pong). - * - * @param cls Closure (unused). - * @param message Message received. - * @param peer Peer who sent the message. - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -int -GMC_handle_kx (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_MessageHeader *message); - -/** - * Core handler for cadet network traffic point-to-point acks. - * - * @param cls closure - * @param message message - * @param peer peer identity this notification is about - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -int -GMC_handle_ack (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_MessageHeader *message); - -/** - * Core handler for cadet network traffic point-to-point ack polls. - * - * @param cls closure - * @param message message - * @param peer peer identity this notification is about - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -int -GMC_handle_poll (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_MessageHeader *message); - -/** - * Core handler for cadet keepalives. - * - * @param cls closure - * @param message message - * @param peer peer identity this notification is about - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - * - * TODO: Check who we got this from, to validate route. - */ -int -GMC_handle_keepalive (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_MessageHeader *message); - -/** - * Send an ACK on the appropriate connection/channel, depending on - * the direction and the position of the peer. - * - * @param c Which connection to send the hop-by-hop ACK. - * @param fwd Is this a fwd ACK? (will go dest->root). - * @param force Send the ACK even if suboptimal (e.g. requested by POLL). - */ -void -GMC_send_ack (struct CadetConnection *c, int fwd, int force); - -/** - * Initialize the connections subsystem - * - * @param c Configuration handle. - */ -void -GMC_init (const struct GNUNET_CONFIGURATION_Handle *c); - -/** - * Shut down the connections subsystem. - */ -void -GMC_shutdown (void); - -/** - * Create a connection. - * - * @param cid Connection ID (either created locally or imposed remotely). - * @param t Tunnel this connection belongs to (or NULL); - * @param p Path this connection has to use. - * @param own_pos Own position in the @c p path. - * - * @return Newly created connection, NULL in case of error (own id not in path). - */ -struct CadetConnection * -GMC_new (const struct GNUNET_CADET_Hash *cid, - struct CadetTunnel3 *t, - struct CadetPeerPath *p, - unsigned int own_pos); - -/** - * Connection is no longer needed: destroy it. - * - * Cancels all pending traffic (including possible DESTROY messages), all - * maintenance tasks and removes the connection from neighbor peers and tunnel. - * - * @param c Connection to destroy. - */ -void -GMC_destroy (struct CadetConnection *c); - -/** - * Get the connection ID. - * - * @param c Connection to get the ID from. - * - * @return ID of the connection. - */ -const struct GNUNET_CADET_Hash * -GMC_get_id (const struct CadetConnection *c); - - -/** - * Get a hash for the connection ID. - * - * @param c Connection to get the hash. - * - * @return Hash expanded from the ID of the connection. - */ -const struct GNUNET_HashCode * -GMC_get_h (const struct CadetConnection *c); - - -/** - * Get the connection path. - * - * @param c Connection to get the path from. - * - * @return path used by the connection. - */ -const struct CadetPeerPath * -GMC_get_path (const struct CadetConnection *c); - -/** - * Get the connection state. - * - * @param c Connection to get the state from. - * - * @return state of the connection. - */ -enum CadetConnectionState -GMC_get_state (const struct CadetConnection *c); - -/** - * Get the connection tunnel. - * - * @param c Connection to get the tunnel from. - * - * @return tunnel of the connection. - */ -struct CadetTunnel3 * -GMC_get_tunnel (const struct CadetConnection *c); - -/** - * Get free buffer space in a connection. - * - * @param c Connection. - * @param fwd Is query about FWD traffic? - * - * @return Free buffer space [0 - max_msgs_queue/max_connections] - */ -unsigned int -GMC_get_buffer (struct CadetConnection *c, int fwd); - -/** - * Get how many messages have we allowed to send to us from a direction. - * - * @param c Connection. - * @param fwd Are we asking about traffic from FWD (BCK messages)? - * - * @return last_ack_sent - last_pid_recv - */ -unsigned int -GMC_get_allowed (struct CadetConnection *c, int fwd); - -/** - * Get messages queued in a connection. - * - * @param c Connection. - * @param fwd Is query about FWD traffic? - * - * @return Number of messages queued. - */ -unsigned int -GMC_get_qn (struct CadetConnection *c, int fwd); - -/** - * Get next PID to use. - * - * @param c Connection. - * @param fwd Is query about FWD traffic? - * - * @return Last PID used + 1. - */ -unsigned int -GMC_get_pid (struct CadetConnection *c, int fwd); - -/** - * Allow the connection to advertise a buffer of the given size. - * - * The connection will send an @c fwd ACK message (so: in direction !fwd) - * allowing up to last_pid_recv + buffer. - * - * @param c Connection. - * @param buffer How many more messages the connection can accept. - * @param fwd Is this about FWD traffic? (The ack will go dest->root). - */ -void -GMC_allow (struct CadetConnection *c, unsigned int buffer, int fwd); - -/** - * Send FWD keepalive packets for a connection. - * - * @param cls Closure (connection for which to send the keepalive). - * @param tc Notification context. - */ -void -GMC_fwd_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - -/** - * Send BCK keepalive packets for a connection. - * - * @param cls Closure (connection for which to send the keepalive). - * @param tc Notification context. - */ -void -GMC_bck_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - - -/** - * Notify other peers on a connection of a broken link. Mark connections - * to destroy after all traffic has been sent. - * - * @param c Connection on which there has been a disconnection. - * @param peer Peer that disconnected. - */ -void -GMC_notify_broken (struct CadetConnection *c, - struct CadetPeer *peer); - -/** - * Is this peer the first one on the connection? - * - * @param c Connection. - * @param fwd Is this about fwd traffic? - * - * @return #GNUNET_YES if origin, #GNUNET_NO if relay/terminal. - */ -int -GMC_is_origin (struct CadetConnection *c, int fwd); - -/** - * Is this peer the last one on the connection? - * - * @param c Connection. - * @param fwd Is this about fwd traffic? - * Note that the ROOT is the terminal for BCK traffic! - * - * @return #GNUNET_YES if terminal, #GNUNET_NO if relay/origin. - */ -int -GMC_is_terminal (struct CadetConnection *c, int fwd); - -/** - * See if we are allowed to send by the next hop in the given direction. - * - * @param c Connection. - * @param fwd Is this about fwd traffic? - * - * @return #GNUNET_YES in case it's OK to send. - */ -int -GMC_is_sendable (struct CadetConnection *c, int fwd); - -/** - * Check if this connection is a direct one (never trim a direct connection). - * - * @param c Connection. - * - * @return #GNUNET_YES in case it's a direct connection, #GNUNET_NO otherwise. - */ -int -GMC_is_direct (struct CadetConnection *c); - -/** - * Cancel a previously sent message while it's in the queue. - * - * ONLY can be called before the continuation given to the send function - * is called. Once the continuation is called, the message is no longer in the - * queue. - * - * @param q Handle to the queue. - */ -void -GMC_cancel (struct CadetConnectionQueue *q); - -/** - * Sends an already built message on a connection, properly registering - * all used resources. - * - * @param message Message to send. Function makes a copy of it. - * If message is not hop-by-hop, decrements TTL of copy. - * @param payload_type Type of payload, in case the message is encrypted. - * @param c Connection on which this message is transmitted. - * @param fwd Is this a fwd message? - * @param force Force the connection to accept the message (buffer overfill). - * @param cont Continuation called once message is sent. Can be NULL. - * @param cont_cls Closure for @c cont. - * - * @return Handle to cancel the message before it's sent. - * NULL on error or if @c cont is NULL. - * Invalid on @c cont call. - */ -struct CadetConnectionQueue * -GMC_send_prebuilt_message (const struct GNUNET_MessageHeader *message, - uint16_t payload_type, uint32_t payload_id, - struct CadetConnection *c, int fwd, int force, - GMC_sent cont, void *cont_cls); - -/** - * Sends a CREATE CONNECTION message for a path to a peer. - * Changes the connection and tunnel states if necessary. - * - * @param connection Connection to create. - */ -void -GMC_send_create (struct CadetConnection *connection); - -/** - * Send a message to all peers in this connection that the connection - * is no longer valid. - * - * If some peer should not receive the message, it should be zero'ed out - * before calling this function. - * - * @param c The connection whose peers to notify. - */ -void -GMC_send_destroy (struct CadetConnection *c); - -/** - * @brief Start a polling timer for the connection. - * - * When a neighbor does not accept more traffic on the connection it could be - * caused by a simple congestion or by a lost ACK. Polling enables to check - * for the lastest ACK status for a connection. - * - * @param c Connection. - * @param fwd Should we poll in the FWD direction? - */ -void -GMC_start_poll (struct CadetConnection *c, int fwd); - - -/** - * @brief Stop polling a connection for ACKs. - * - * Once we have enough ACKs for future traffic, polls are no longer necessary. - * - * @param c Connection. - * @param fwd Should we stop the poll in the FWD direction? - */ -void -GMC_stop_poll (struct CadetConnection *c, int fwd); - -/** - * Get a (static) string for a connection. - * - * @param c Connection. - */ -const char * -GMC_2s (const struct CadetConnection *c); - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_SERVICE_CADET_CONNECTION_H */ -#endif -/* end of gnunet-service-cadet_connection.h */ diff --git a/src/mesh/gnunet-service-cadet_dht.c b/src/mesh/gnunet-service-cadet_dht.c deleted file mode 100644 index b187e3cd9..000000000 --- a/src/mesh/gnunet-service-cadet_dht.c +++ /dev/null @@ -1,423 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2013 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_util_lib.h" - -#include "gnunet_dht_service.h" -#include "gnunet_statistics_service.h" - -#include "cadet_path.h" -#include "gnunet-service-cadet_dht.h" -#include "gnunet-service-cadet_peer.h" -#include "gnunet-service-cadet_hello.h" - -#define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__) - - -/******************************************************************************/ -/******************************** STRUCTS **********************************/ -/******************************************************************************/ - -/** - * Handle for DHT searches. - */ -struct GMD_search_handle -{ - /** DHT_GET handle. */ - struct GNUNET_DHT_GetHandle *dhtget; - - /** Provided callback to call when a path is found. */ - GMD_search_callback callback; - - /** Provided closure. */ - void *cls; - - /** Peer ID searched for */ - GNUNET_PEER_Id peer_id; -}; - - -/******************************************************************************/ -/******************************* GLOBALS ***********************************/ -/******************************************************************************/ - -/** - * Global handle to the statistics service. - */ -extern struct GNUNET_STATISTICS_Handle *stats; - -/** - * Own ID (short value). - */ -extern GNUNET_PEER_Id myid; - -/** - * Own ID (full value). - */ -extern struct GNUNET_PeerIdentity my_full_id; - -/** - * Handle to use DHT. - */ -static struct GNUNET_DHT_Handle *dht_handle; - -/** - * How often to PUT own ID in the DHT. - */ -static struct GNUNET_TIME_Relative id_announce_time; - -/** - * DHT replication level, see DHT API: GNUNET_DHT_get_start, GNUNET_DHT_put. - */ -static unsigned long long dht_replication_level; - -/** - * Task to periodically announce itself in the network. - */ -static GNUNET_SCHEDULER_TaskIdentifier announce_id_task; - -/** - * GET requests to stop on shutdown. - */ -static struct GNUNET_CONTAINER_MultiHashMap32 *get_requests; - -/******************************************************************************/ -/******************************** STATIC ***********************************/ -/******************************************************************************/ - - -/** - * Build a PeerPath from the paths returned from the DHT, reversing the paths - * to obtain a local peer -> destination path and interning the peer ids. - * - * @return Newly allocated and created path - * - * FIXME refactor and use build_path_from_peer_ids - */ -static struct CadetPeerPath * -path_build_from_dht (const struct GNUNET_PeerIdentity *get_path, - unsigned int get_path_length, - const struct GNUNET_PeerIdentity *put_path, - unsigned int put_path_length) -{ - struct CadetPeerPath *p; - GNUNET_PEER_Id id; - int i; - - p = path_new (1); - p->peers[0] = myid; - GNUNET_PEER_change_rc (myid, 1); - i = get_path_length; - LOG (GNUNET_ERROR_TYPE_DEBUG, " GET has %d hops.\n", i); - for (i--; i >= 0; i--) - { - id = GNUNET_PEER_intern (&get_path[i]); - if (p->length > 0 && id == p->peers[p->length - 1]) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n"); - GNUNET_PEER_change_rc (id, -1); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " Adding from GET: %s.\n", - GNUNET_i2s (&get_path[i])); - p->length++; - p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length); - p->peers[p->length - 1] = id; - } - } - i = put_path_length; - LOG (GNUNET_ERROR_TYPE_DEBUG, " PUT has %d hops.\n", i); - for (i--; i >= 0; i--) - { - id = GNUNET_PEER_intern (&put_path[i]); - if (id == myid) - { - /* PUT path went through us, so discard the path up until now and start - * from here to get a much shorter (and loop-free) path. - */ - path_destroy (p); - p = path_new (0); - } - if (p->length > 0 && id == p->peers[p->length - 1]) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n"); - GNUNET_PEER_change_rc (id, -1); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " Adding from PUT: %s.\n", - GNUNET_i2s (&put_path[i])); - p->length++; - p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length); - p->peers[p->length - 1] = id; - } - } -#if CADET_DEBUG - if (get_path_length > 0) - LOG (GNUNET_ERROR_TYPE_DEBUG, " (first of GET: %s)\n", - GNUNET_i2s (&get_path[0])); - if (put_path_length > 0) - LOG (GNUNET_ERROR_TYPE_DEBUG, " (first of PUT: %s)\n", - GNUNET_i2s (&put_path[0])); - LOG (GNUNET_ERROR_TYPE_DEBUG, " In total: %d hops\n", - p->length); - for (i = 0; i < p->length; i++) - { - struct GNUNET_PeerIdentity peer_id; - - GNUNET_PEER_resolve (p->peers[i], &peer_id); - LOG (GNUNET_ERROR_TYPE_DEBUG, " %u: %s\n", p->peers[i], - GNUNET_i2s (&peer_id)); - } -#endif - return p; -} - - -/** - * Function to process paths received for a new peer addition. The recorded - * paths form the initial tunnel, which can be optimized later. - * Called on each result obtained for the DHT search. - * - * @param cls closure - * @param exp when will this value expire - * @param key key of the result - * @param get_path path of the get request - * @param get_path_length lenght of get_path - * @param put_path path of the put request - * @param put_path_length length of the put_path - * @param type type of the result - * @param size number of bytes in data - * @param data pointer to the result data - */ -static void -dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp, - const struct GNUNET_HashCode * key, - const struct GNUNET_PeerIdentity *get_path, - unsigned int get_path_length, - const struct GNUNET_PeerIdentity *put_path, - unsigned int put_path_length, enum GNUNET_BLOCK_Type type, - size_t size, const void *data) -{ - struct GMD_search_handle *h = cls; - struct GNUNET_HELLO_Message *hello; - struct CadetPeerPath *p; - struct CadetPeer *peer; - char *s; - - p = path_build_from_dht (get_path, get_path_length, - put_path, put_path_length); - s = path_2s (p); - LOG (GNUNET_ERROR_TYPE_INFO, "Got path from DHT: %s\n", s); - GNUNET_free_non_null (s); - peer = GMP_get_short (p->peers[p->length - 1]); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Got HELLO for %s\n", GMP_2s (peer)); - h->callback (h->cls, p); - path_destroy (p); - hello = (struct GNUNET_HELLO_Message *) data; - GMP_set_hello (peer, hello); - GMP_try_connect (peer); - return; -} - - -/** - * Periodically announce self id in the DHT - * - * @param cls closure - * @param tc task context - */ -static void -announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_HashCode phash; - const struct GNUNET_HELLO_Message *hello; - size_t size; - struct GNUNET_TIME_Absolute expiration; - struct GNUNET_TIME_Relative retry_time; - - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - { - announce_id_task = GNUNET_SCHEDULER_NO_TASK; - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, "Announce ID\n"); - - /* TODO - * - Set data expiration in function of X - * - Adapt X to churn - */ - hello = GMH_get_mine (); - if (NULL == hello || (size = GNUNET_HELLO_size (hello)) == 0) - { - /* Peerinfo gave us no hello yet, try again in a second. */ - announce_id_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, - &announce_id, cls); - LOG (GNUNET_ERROR_TYPE_DEBUG, " no hello, waiting!\n"); - return; - } - expiration = GNUNET_HELLO_get_last_expiration (hello); - retry_time = GNUNET_TIME_absolute_get_remaining (expiration); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Hello %p size: %u\n", hello, size); - memset (&phash, 0, sizeof (phash)); - memcpy (&phash, &my_full_id, sizeof (my_full_id)); - GNUNET_DHT_put (dht_handle, /* DHT handle */ - &phash, /* Key to use */ - dht_replication_level, /* Replication level */ - GNUNET_DHT_RO_RECORD_ROUTE - | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */ - GNUNET_BLOCK_TYPE_DHT_HELLO, /* Block type */ - size, /* Size of the data */ - (const char *) hello, /* Data itself */ - expiration, /* Data expiration */ - retry_time, /* Retry time */ - NULL, /* Continuation */ - NULL); /* Continuation closure */ - announce_id_task = - GNUNET_SCHEDULER_add_delayed (id_announce_time, &announce_id, cls); -} - -/** - * Iterator over hash map entries and stop GET requests before disconnecting - * from the DHT. - * - * @param cls Closure (unused) - * @param key Current peer ID. - * @param value Value in the hash map (GMD_search_handle). - * - * @return #GNUNET_YES, we should continue to iterate, - */ -int -stop_get (void *cls, - uint32_t key, - void *value) -{ - struct GMD_search_handle *h = value; - - GMD_search_stop (h); - return GNUNET_YES; -} - - -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ - -/** - * Initialize the DHT subsystem. - * - * @param c Configuration. - */ -void -GMD_init (const struct GNUNET_CONFIGURATION_Handle *c) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (c, "CADET", "DHT_REPLICATION_LEVEL", - &dht_replication_level)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, - "CADET", "DHT_REPLICATION_LEVEL", "USING DEFAULT"); - dht_replication_level = 3; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (c, "CADET", "ID_ANNOUNCE_TIME", - &id_announce_time)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "CADET", "ID_ANNOUNCE_TIME", "MISSING"); - GNUNET_SCHEDULER_shutdown (); - return; - } - - dht_handle = GNUNET_DHT_connect (c, 64); - if (NULL == dht_handle) - { - GNUNET_break (0); - } - - announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL); - get_requests = GNUNET_CONTAINER_multihashmap32_create (32); -} - - -/** - * Shut down the DHT subsystem. - */ -void -GMD_shutdown (void) -{ - GNUNET_CONTAINER_multihashmap32_iterate (get_requests, &stop_get, NULL); - GNUNET_CONTAINER_multihashmap32_destroy (get_requests); - if (dht_handle != NULL) - { - GNUNET_DHT_disconnect (dht_handle); - dht_handle = NULL; - } - if (GNUNET_SCHEDULER_NO_TASK != announce_id_task) - { - GNUNET_SCHEDULER_cancel (announce_id_task); - announce_id_task = GNUNET_SCHEDULER_NO_TASK; - } -} - -struct GMD_search_handle * -GMD_search (const struct GNUNET_PeerIdentity *peer_id, - GMD_search_callback callback, void *cls) -{ - struct GNUNET_HashCode phash; - struct GMD_search_handle *h; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - " Starting DHT GET for peer %s\n", GNUNET_i2s (peer_id)); - memset (&phash, 0, sizeof (phash)); - memcpy (&phash, peer_id, sizeof (*peer_id)); - h = GNUNET_new (struct GMD_search_handle); - h->peer_id = GNUNET_PEER_intern (peer_id); - h->callback = callback; - h->cls = cls; - h->dhtget = GNUNET_DHT_get_start (dht_handle, /* handle */ - GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */ - &phash, /* key to search */ - dht_replication_level, /* replication level */ - GNUNET_DHT_RO_RECORD_ROUTE | - GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, - NULL, /* xquery */ - 0, /* xquery bits */ - &dht_get_id_handler, h); - GNUNET_CONTAINER_multihashmap32_put (get_requests, h->peer_id, h, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - return h; -} - -void -GMD_search_stop (struct GMD_search_handle *h) -{ - GNUNET_break (GNUNET_OK == - GNUNET_CONTAINER_multihashmap32_remove (get_requests, - h->peer_id, h)); - GNUNET_DHT_get_stop (h->dhtget); - GNUNET_free (h); -} diff --git a/src/mesh/gnunet-service-cadet_dht.h b/src/mesh/gnunet-service-cadet_dht.h deleted file mode 100644 index 6cac531ff..000000000 --- a/src/mesh/gnunet-service-cadet_dht.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2013 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 cadet/gnunet-service-cadet_dht.h - * @brief cadet service; dealing with DHT requests and results - * @author Bartlomiej Polot - * - * All functions in this file should use the prefix GMD (Gnunet Cadet Dht) - */ - -#ifndef GNUNET_SERVICE_CADET_DHT_H -#define GNUNET_SERVICE_CADET_DHT_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "platform.h" -#include "gnunet_util_lib.h" - -struct GMD_search_handle; - - -/** - * Callback called on each path found over the DHT. - * - * @param cls Closure. - * @param path An unchecked, unoptimized path to the target node. - * After callback will no longer be valid! - */ -typedef void (*GMD_search_callback) (void *cls, - const struct CadetPeerPath *path); - -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ - -/** - * Initialize the DHT subsystem. - * - * @param c Configuration. - */ -void -GMD_init (const struct GNUNET_CONFIGURATION_Handle *c); - -/** - * Shut down the DHT subsystem. - */ -void -GMD_shutdown (void); - - -struct GMD_search_handle * -GMD_search (const struct GNUNET_PeerIdentity *peer_id, - GMD_search_callback callback, void *cls); - - -void -GMD_search_stop (struct GMD_search_handle *h); - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_CADET_SERVICE_LOCAL_H */ -#endif -/* end of gnunet-cadet-service_LOCAL.h */ \ No newline at end of file diff --git a/src/mesh/gnunet-service-cadet_hello.c b/src/mesh/gnunet-service-cadet_hello.c deleted file mode 100644 index 7eda3f507..000000000 --- a/src/mesh/gnunet-service-cadet_hello.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2014 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_util_lib.h" - -#include "gnunet_statistics_service.h" -#include "gnunet_peerinfo_service.h" - -#include "cadet_protocol.h" -#include "cadet_path.h" - -#include "gnunet-service-cadet_hello.h" -#include "gnunet-service-cadet_peer.h" - -#define LOG(level, ...) GNUNET_log_from(level,"cadet-hll",__VA_ARGS__) - - -/******************************************************************************/ -/******************************** STRUCTS **********************************/ -/******************************************************************************/ - - - -/******************************************************************************/ -/******************************* GLOBALS ***********************************/ -/******************************************************************************/ - -/** - * Global handle to the statistics service. - */ -extern struct GNUNET_STATISTICS_Handle *stats; - -/** - * Local peer own ID (memory efficient handle). - */ -extern GNUNET_PEER_Id myid; - -/** - * Local peer own ID (full value). - */ -extern struct GNUNET_PeerIdentity my_full_id; - - -/** - * Don't try to recover tunnels if shutting down. - */ -extern int shutting_down; - - -/** - * Hello message of local peer. - */ -const struct GNUNET_HELLO_Message *mine; - -/** - * Handle to peerinfo service. - */ -static struct GNUNET_PEERINFO_Handle *peerinfo; - -/** - * Iterator context. - */ -struct GNUNET_PEERINFO_NotifyContext* nc; - - -/******************************************************************************/ -/******************************** STATIC ***********************************/ -/******************************************************************************/ - -/** - * Process each hello message received from peerinfo. - * - * @param cls Closure (unused). - * @param peer Identity of the peer. - * @param hello Hello of the peer. - * @param err_msg Error message. - */ -static void -got_hello (void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_HELLO_Message *hello, - const char *err_msg) -{ - struct CadetPeer *peer; - - if (NULL == id || NULL == hello) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " hello with id %p and msg %p\n", id, hello); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " hello for %s (%d bytes), expires on %s\n", - GNUNET_i2s (id), GNUNET_HELLO_size (hello), - GNUNET_STRINGS_absolute_time_to_string (GNUNET_HELLO_get_last_expiration(hello))); - peer = GMP_get (id); - GMP_set_hello (peer, hello); - - if (GMP_get_short_id (peer) == myid) - { - mine = GMP_get_hello (peer); - LOG (GNUNET_ERROR_TYPE_DEBUG, " updated mine to %p\n", mine); - } -} - - -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ - -/** - * Initialize the hello subsystem. - * - * @param c Configuration. - */ -void -GMH_init (const struct GNUNET_CONFIGURATION_Handle *c) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); - GNUNET_assert (NULL == nc); - peerinfo = GNUNET_PEERINFO_connect (c); - nc = GNUNET_PEERINFO_notify (c, GNUNET_NO, &got_hello, NULL); -} - - -/** - * Shut down the hello subsystem. - */ -void -GMH_shutdown () -{ - if (NULL != nc) - { - GNUNET_PEERINFO_notify_cancel (nc); - nc = NULL; - } - if (NULL != peerinfo) - { - GNUNET_PEERINFO_disconnect (peerinfo); - peerinfo = NULL; - } -} - - -/** - * Get own hello message. - * - * @return Own hello message. - */ -const struct GNUNET_HELLO_Message * -GMH_get_mine (void) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, " mine is %p\n", mine); - return mine; -} - - -/** - * Get another peer's hello message. - * - * @param id ID of the peer whose hello message is requested. - * - * @return Hello message, if any (NULL possible). - */ -const struct GNUNET_HELLO_Message * -GMH_get (const struct GNUNET_PeerIdentity *id) -{ - return GMP_get_hello (GMP_get (id)); -} - - -/** - * Convert a hello message to a string. - * - * @param h Hello message. - */ -char * -GMH_2s (const struct GNUNET_HELLO_Message *h) -{ - return "hello (TODO)"; -} - - diff --git a/src/mesh/gnunet-service-cadet_hello.h b/src/mesh/gnunet-service-cadet_hello.h deleted file mode 100644 index 8e978ea9d..000000000 --- a/src/mesh/gnunet-service-cadet_hello.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2014 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 cadet/gnunet-service-cadet_hello.h - * @brief cadet service; dealing with hello messages - * @author Bartlomiej Polot - * - * All functions in this file should use the prefix GMH (Gnunet Cadet Hello) - */ - -#ifndef GNUNET_SERVICE_CADET_HELLO_H -#define GNUNET_SERVICE_CADET_HELLO_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_hello_lib.h" - - -/** - * Initialize the hello subsystem. - * - * @param c Configuration. - */ -void -GMH_init (const struct GNUNET_CONFIGURATION_Handle *c); - -/** - * Shut down the hello subsystem. - */ -void -GMH_shutdown (); - -/** - * Get own hello message. - * - * @return Own hello message. - */ -const struct GNUNET_HELLO_Message * -GMH_get_mine (void); - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_CADET_SERVICE_HELLO_H */ -#endif -/* end of gnunet-cadet-service_hello.h */ diff --git a/src/mesh/gnunet-service-cadet_local.c b/src/mesh/gnunet-service-cadet_local.c deleted file mode 100644 index 96596ce68..000000000 --- a/src/mesh/gnunet-service-cadet_local.c +++ /dev/null @@ -1,1242 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2013 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_util_lib.h" - -#include "gnunet_statistics_service.h" - -#include "cadet.h" -#include "cadet_protocol.h" /* GNUNET_CADET_Data is shared */ - -#include "gnunet-service-cadet_local.h" -#include "gnunet-service-cadet_channel.h" - -/* INFO DEBUG */ -#include "gnunet-service-cadet_tunnel.h" -#include "gnunet-service-cadet_peer.h" - -#define LOG(level, ...) GNUNET_log_from(level,"cadet-loc",__VA_ARGS__) - -/******************************************************************************/ -/******************************** STRUCTS **********************************/ -/******************************************************************************/ - -/** - * Struct containing information about a client of the service - * - * TODO: add a list of 'waiting' ports - */ -struct CadetClient -{ - /** - * Linked list next - */ - struct CadetClient *next; - - /** - * Linked list prev - */ - struct CadetClient *prev; - - /** - * Tunnels that belong to this client, indexed by local id - */ - struct GNUNET_CONTAINER_MultiHashMap32 *own_channels; - - /** - * Tunnels this client has accepted, indexed by incoming local id - */ - struct GNUNET_CONTAINER_MultiHashMap32 *incoming_channels; - - /** - * Channel ID for the next incoming channel. - */ - CADET_ChannelNumber next_chid; - - /** - * Handle to communicate with the client - */ - struct GNUNET_SERVER_Client *handle; - - /** - * Ports that this client has declared interest in. - * Indexed by port, contains *Client. - */ - struct GNUNET_CONTAINER_MultiHashMap32 *ports; - - /** - * Whether the client is active or shutting down (don't send confirmations - * to a client that is shutting down. - */ - int shutting_down; - - /** - * ID of the client, mainly for debug messages - */ - unsigned int id; -}; - -/******************************************************************************/ -/******************************* GLOBALS ***********************************/ -/******************************************************************************/ - -/** - * Global handle to the statistics service. - */ -extern struct GNUNET_STATISTICS_Handle *stats; - -/** - * Handle to server lib. - */ -static struct GNUNET_SERVER_Handle *server_handle; - -/** - * DLL with all the clients, head. - */ -static struct CadetClient *clients_head; - -/** - * DLL with all the clients, tail. - */ -static struct CadetClient *clients_tail; - -/** - * Next ID to assign to a client. - */ -unsigned int next_client_id; - -/** - * All ports clients of this peer have opened. - */ -static struct GNUNET_CONTAINER_MultiHashMap32 *ports; - -/** - * Notification context, to send messages to local clients. - */ -static struct GNUNET_SERVER_NotificationContext *nc; - - -/******************************************************************************/ -/******************************** STATIC ***********************************/ -/******************************************************************************/ - -/** - * Remove client's ports from the global hashmap on disconnect. - * - * @param cls Closure (unused). - * @param key Port. - * @param value Client structure. - * - * @return GNUNET_OK, keep iterating. - */ -static int -client_release_ports (void *cls, - uint32_t key, - void *value) -{ - int res; - - res = GNUNET_CONTAINER_multihashmap32_remove (ports, key, value); - if (GNUNET_YES != res) - { - GNUNET_break (0); - LOG (GNUNET_ERROR_TYPE_WARNING, - "Port %u by client %p was not registered.\n", - key, value); - } - return GNUNET_OK; -} - - - -/******************************************************************************/ -/******************************** HANDLES ***********************************/ -/******************************************************************************/ - - -/** - * Handler for client connection. - * - * @param cls Closure (unused). - * @param client Client handler. - */ -static void -handle_client_connect (void *cls, struct GNUNET_SERVER_Client *client) -{ - struct CadetClient *c; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "client connected: %p\n", client); - if (NULL == client) - return; - c = GNUNET_new (struct CadetClient); - c->handle = client; - c->id = next_client_id++; /* overflow not important: just for debug */ - c->next_chid = GNUNET_CADET_LOCAL_CHANNEL_ID_SERV; - GNUNET_SERVER_client_keep (client); - GNUNET_SERVER_client_set_user_context (client, c); - GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, c); -} - - -/** - * Iterator for deleting each channel whose client endpoint disconnected. - * - * @param cls Closure (client that has disconnected). - * @param key The local channel id (used to access the hashmap). - * @param value The value stored at the key (channel to destroy). - * - * @return GNUNET_OK, keep iterating. - */ -static int -channel_destroy_iterator (void *cls, - uint32_t key, - void *value) -{ - struct CadetChannel *ch = value; - struct CadetClient *c = cls; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - " Channel %s destroy, due to client %s shutdown.\n", - GMCH_2s (ch), GML_2s (c)); - - GMCH_handle_local_destroy (ch, c, key < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV); - return GNUNET_OK; -} - -/** - * Handler for client disconnection - * - * @param cls closure - * @param client identification of the client; NULL - * for the last call when the server is destroyed - */ -static void -handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) -{ - struct CadetClient *c; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "client disconnected: %p\n", client); - if (client == NULL) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " (SERVER DOWN)\n"); - return; - } - - c = GML_client_get (client); - if (NULL != c) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "matching client found (%u, %p)\n", - c->id, c); - GNUNET_SERVER_client_drop (c->handle); - c->shutting_down = GNUNET_YES; - if (NULL != c->own_channels) - { - GNUNET_CONTAINER_multihashmap32_iterate (c->own_channels, - &channel_destroy_iterator, c); - GNUNET_CONTAINER_multihashmap32_destroy (c->own_channels); - } - - if (NULL != c->incoming_channels) - { - GNUNET_CONTAINER_multihashmap32_iterate (c->incoming_channels, - &channel_destroy_iterator, c); - GNUNET_CONTAINER_multihashmap32_destroy (c->incoming_channels); - } - - if (NULL != c->ports) - { - GNUNET_CONTAINER_multihashmap32_iterate (c->ports, - &client_release_ports, c); - GNUNET_CONTAINER_multihashmap32_destroy (c->ports); - } - GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, c); - GNUNET_STATISTICS_update (stats, "# clients", -1, GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_DEBUG, " client free (%p)\n", c); - GNUNET_free (c); - } - else - { - LOG (GNUNET_ERROR_TYPE_WARNING, " context NULL!\n"); - } - LOG (GNUNET_ERROR_TYPE_DEBUG, "done!\n"); - return; -} - - -/** - * Handler for new clients - * - * @param cls closure - * @param client identification of the client - * @param message the actual message, which includes messages the client wants - */ -static void -handle_new_client (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct GNUNET_CADET_ClientConnect *cc_msg; - struct CadetClient *c; - unsigned int size; - uint32_t *p; - unsigned int i; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); - LOG (GNUNET_ERROR_TYPE_DEBUG, "new client connected %p\n", client); - - /* Check data sanity */ - size = ntohs (message->size) - sizeof (struct GNUNET_CADET_ClientConnect); - cc_msg = (struct GNUNET_CADET_ClientConnect *) message; - if (0 != (size % sizeof (uint32_t))) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - size /= sizeof (uint32_t); - - /* Initialize new client structure */ - c = GNUNET_SERVER_client_get_user_context (client, struct CadetClient); - LOG (GNUNET_ERROR_TYPE_DEBUG, " client id %u\n", c->id); - LOG (GNUNET_ERROR_TYPE_DEBUG, " client has %u ports\n", size); - if (size > 0) - { - uint32_t u32; - - p = (uint32_t *) &cc_msg[1]; - c->ports = GNUNET_CONTAINER_multihashmap32_create (size); - for (i = 0; i < size; i++) - { - u32 = ntohl (p[i]); - LOG (GNUNET_ERROR_TYPE_DEBUG, " port: %u\n", u32); - - /* store in client's hashmap */ - GNUNET_CONTAINER_multihashmap32_put (c->ports, u32, c, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - /* store in global hashmap */ - /* FIXME only allow one client to have the port open, - * have a backup hashmap with waiting clients */ - GNUNET_CONTAINER_multihashmap32_put (ports, u32, c, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - } - } - - c->own_channels = GNUNET_CONTAINER_multihashmap32_create (32); - c->incoming_channels = GNUNET_CONTAINER_multihashmap32_create (32); - GNUNET_SERVER_notification_context_add (nc, client); - GNUNET_STATISTICS_update (stats, "# clients", 1, GNUNET_NO); - - GNUNET_SERVER_receive_done (client, GNUNET_OK); - LOG (GNUNET_ERROR_TYPE_DEBUG, "new client processed\n"); -} - - -/** - * Handler for requests of new tunnels - * - * @param cls Closure. - * @param client Identification of the client. - * @param message The actual message. - */ -static void -handle_channel_create (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct CadetClient *c; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); - LOG (GNUNET_ERROR_TYPE_DEBUG, "new channel requested\n"); - - /* Sanity check for client registration */ - if (NULL == (c = GML_client_get (client))) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); - - /* Message size sanity check */ - if (sizeof (struct GNUNET_CADET_ChannelMessage) != ntohs (message->size)) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - if (GNUNET_OK != - GMCH_handle_local_create (c, - (struct GNUNET_CADET_ChannelMessage *) message)) - { - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - GNUNET_SERVER_receive_done (client, GNUNET_OK); - return; -} - - -/** - * Handler for requests of deleting tunnels - * - * @param cls closure - * @param client identification of the client - * @param message the actual message - */ -static void -handle_channel_destroy (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct GNUNET_CADET_ChannelMessage *msg; - struct CadetClient *c; - struct CadetChannel *ch; - CADET_ChannelNumber chid; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a DESTROY CHANNEL from client!\n"); - - /* Sanity check for client registration */ - if (NULL == (c = GML_client_get (client))) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); - - /* Message sanity check */ - if (sizeof (struct GNUNET_CADET_ChannelMessage) != ntohs (message->size)) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - msg = (struct GNUNET_CADET_ChannelMessage *) message; - - /* Retrieve tunnel */ - chid = ntohl (msg->channel_id); - LOG (GNUNET_ERROR_TYPE_DEBUG, " for channel %X\n", chid); - ch = GML_channel_get (c, chid); - if (NULL == ch) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " channel %X not found\n", chid); - GNUNET_STATISTICS_update (stats, - "# client destroy messages on unknown channel", - 1, GNUNET_NO); - GNUNET_SERVER_receive_done (client, GNUNET_OK); - return; - } - - GMCH_handle_local_destroy (ch, c, chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV); - - GNUNET_SERVER_receive_done (client, GNUNET_OK); - return; -} - - -/** - * Handler for client traffic - * - * @param cls closure - * @param client identification of the client - * @param message the actual message - */ -static void -handle_data (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct GNUNET_CADET_LocalData *msg; - struct CadetClient *c; - struct CadetChannel *ch; - CADET_ChannelNumber chid; - size_t size; - int fwd; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Got data from a client!\n"); - - /* Sanity check for client registration */ - if (NULL == (c = GML_client_get (client))) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); - - msg = (struct GNUNET_CADET_LocalData *) message; - - /* Sanity check for message size */ - size = ntohs (message->size) - sizeof (struct GNUNET_CADET_LocalData); - if (size < sizeof (struct GNUNET_MessageHeader)) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - /* Channel exists? */ - chid = ntohl (msg->id); - LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X\n", chid); - fwd = chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV; - ch = GML_channel_get (c, chid); - if (NULL == ch) - { - GNUNET_STATISTICS_update (stats, - "# client data messages on unknown channel", - 1, GNUNET_NO); - GNUNET_SERVER_receive_done (client, GNUNET_OK); - return; - } - - if (GNUNET_OK != - GMCH_handle_local_data (ch, c, - (struct GNUNET_MessageHeader *)&msg[1], fwd)) - { - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, "receive done OK\n"); - GNUNET_SERVER_receive_done (client, GNUNET_OK); - - return; -} - - -/** - * Handler for client's ACKs for payload traffic. - * - * @param cls Closure (unused). - * @param client Identification of the client. - * @param message The actual message. - */ -static void -handle_ack (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct GNUNET_CADET_LocalAck *msg; - struct CadetChannel *ch; - struct CadetClient *c; - CADET_ChannelNumber chid; - int fwd; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a local ACK\n"); - - /* Sanity check for client registration */ - if (NULL == (c = GML_client_get (client))) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); - - msg = (struct GNUNET_CADET_LocalAck *) message; - - /* Channel exists? */ - chid = ntohl (msg->channel_id); - LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X\n", chid); - ch = GML_channel_get (c, chid); - LOG (GNUNET_ERROR_TYPE_DEBUG, " -- ch %p\n", ch); - if (NULL == ch) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %X unknown.\n", chid); - LOG (GNUNET_ERROR_TYPE_DEBUG, " for client %u.\n", c->id); - GNUNET_STATISTICS_update (stats, - "# client ack messages on unknown channel", - 1, GNUNET_NO); - GNUNET_SERVER_receive_done (client, GNUNET_OK); - return; - } - - /* If client is root, the ACK is going FWD, therefore this is "BCK ACK". */ - /* If client is dest, the ACK is going BCK, therefore this is "FWD ACK" */ - fwd = chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV; - - GMCH_handle_local_ack (ch, fwd); - GNUNET_SERVER_receive_done (client, GNUNET_OK); - - return; -} - - - -/** - * Iterator over all peers to send a monitoring client info about each peer. - * - * @param cls Closure (). - * @param peer Peer ID (tunnel remote peer). - * @param value Peer info. - * - * @return #GNUNET_YES, to keep iterating. - */ -static int -get_all_peers_iterator (void *cls, - const struct GNUNET_PeerIdentity * peer, - void *value) -{ - struct GNUNET_SERVER_Client *client = cls; - struct CadetPeer *p = value; - struct GNUNET_CADET_LocalInfoPeer msg; - - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS); - msg.destination = *peer; - msg.paths = htons (GMP_count_paths (p)); - msg.tunnel = htons (NULL != GMP_get_tunnel (p)); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "sending info about peer %s\n", - GNUNET_i2s (peer)); - - GNUNET_SERVER_notification_context_unicast (nc, client, - &msg.header, GNUNET_NO); - return GNUNET_YES; -} - - -/** - * Handler for client's INFO PEERS request. - * - * @param cls Closure (unused). - * @param client Identification of the client. - * @param message The actual message. - */ -static void -handle_get_peers (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct CadetClient *c; - struct GNUNET_MessageHeader reply; - - /* Sanity check for client registration */ - if (NULL == (c = GML_client_get (client))) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received get peers request from client %u (%p)\n", - c->id, client); - - GMP_iterate_all (get_all_peers_iterator, client); - reply.size = htons (sizeof (reply)); - reply.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS); - GNUNET_SERVER_notification_context_unicast (nc, client, &reply, GNUNET_NO); - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Get peers request from client %u completed\n", c->id); - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -/** - * Iterator over all tunnels to send a monitoring client info about each tunnel. - * - * @param cls Closure (). - * @param peer Peer ID (tunnel remote peer). - * @param value Tunnel info. - * - * @return #GNUNET_YES, to keep iterating. - */ -static int -get_all_tunnels_iterator (void *cls, - const struct GNUNET_PeerIdentity * peer, - void *value) -{ - struct GNUNET_SERVER_Client *client = cls; - struct CadetTunnel3 *t = value; - struct GNUNET_CADET_LocalInfoTunnel msg; - - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS); - msg.destination = *peer; - msg.channels = htonl (GMT_count_channels (t)); - msg.connections = htonl (GMT_count_connections (t)); - msg.cstate = htons ((uint16_t) GMT_get_cstate (t)); - msg.estate = htons ((uint16_t) GMT_get_estate (t)); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "sending info about tunnel ->%s\n", - GNUNET_i2s (peer)); - - GNUNET_SERVER_notification_context_unicast (nc, client, - &msg.header, GNUNET_NO); - return GNUNET_YES; -} - - -/** - * Handler for client's INFO TUNNELS request. - * - * @param cls Closure (unused). - * @param client Identification of the client. - * @param message The actual message. - */ -static void -handle_get_tunnels (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct CadetClient *c; - struct GNUNET_MessageHeader reply; - - /* Sanity check for client registration */ - if (NULL == (c = GML_client_get (client))) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received get tunnels request from client %u (%p)\n", - c->id, client); - - GMT_iterate_all (get_all_tunnels_iterator, client); - reply.size = htons (sizeof (reply)); - reply.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS); - GNUNET_SERVER_notification_context_unicast (nc, client, &reply, GNUNET_NO); - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Get tunnels request from client %u completed\n", c->id); - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -static void -iter_connection (void *cls, struct CadetConnection *c) -{ - struct GNUNET_CADET_LocalInfoTunnel *msg = cls; - struct GNUNET_CADET_Hash *h = (struct GNUNET_CADET_Hash *) &msg[1]; - - h[msg->connections] = *(GMC_get_id (c)); - msg->connections++; -} - -static void -iter_channel (void *cls, struct CadetChannel *ch) -{ - struct GNUNET_CADET_LocalInfoTunnel *msg = cls; - struct GNUNET_HashCode *h = (struct GNUNET_HashCode *) &msg[1]; - CADET_ChannelNumber *chn = (CADET_ChannelNumber *) &h[msg->connections]; - - chn[msg->channels] = GMCH_get_id (ch); - msg->channels++; -} - - -/** - * Handler for client's SHOW_TUNNEL request. - * - * @param cls Closure (unused). - * @param client Identification of the client. - * @param message The actual message. - */ -void -handle_show_tunnel (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - const struct GNUNET_CADET_LocalInfo *msg; - struct GNUNET_CADET_LocalInfoTunnel *resp; - struct CadetClient *c; - struct CadetTunnel3 *t; - unsigned int ch_n; - unsigned int c_n; - size_t size; - - /* Sanity check for client registration */ - if (NULL == (c = GML_client_get (client))) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - msg = (struct GNUNET_CADET_LocalInfo *) message; - LOG (GNUNET_ERROR_TYPE_INFO, - "Received tunnel info request from client %u for tunnel %s\n", - c->id, GNUNET_i2s_full(&msg->peer)); - - t = GMP_get_tunnel (GMP_get (&msg->peer)); - if (NULL == t) - { - /* We don't know the tunnel */ - struct GNUNET_CADET_LocalInfoTunnel warn; - - LOG (GNUNET_ERROR_TYPE_INFO, "Tunnel %s unknown %u\n", - GNUNET_i2s_full(&msg->peer), sizeof (warn)); - warn.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL); - warn.header.size = htons (sizeof (warn)); - warn.destination = msg->peer; - warn.channels = htonl (0); - warn.connections = htonl (0); - warn.cstate = htons (0); - warn.estate = htons (0); - - GNUNET_SERVER_notification_context_unicast (nc, client, - &warn.header, - GNUNET_NO); - GNUNET_SERVER_receive_done (client, GNUNET_OK); - return; - } - - /* Initialize context */ - ch_n = GMT_count_channels (t); - c_n = GMT_count_connections (t); - - size = sizeof (struct GNUNET_CADET_LocalInfoTunnel); - size += c_n * sizeof (struct GNUNET_CADET_Hash); - size += ch_n * sizeof (CADET_ChannelNumber); - - resp = GNUNET_malloc (size); - resp->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL); - resp->header.size = htons (size); - GMT_iterate_connections (t, &iter_connection, resp); - GMT_iterate_channels (t, &iter_channel, resp); - /* Do not interleave with iterators, iter_channel needs conn in HBO */ - resp->destination = msg->peer; - resp->connections = htonl (resp->connections); - resp->channels = htonl (resp->channels); - resp->cstate = htons (GMT_get_cstate (t)); - resp->estate = htons (GMT_get_estate (t)); - GNUNET_SERVER_notification_context_unicast (nc, c->handle, - &resp->header, GNUNET_NO); - GNUNET_free (resp); - - LOG (GNUNET_ERROR_TYPE_INFO, - "Show tunnel request from client %u completed. %u conn, %u ch\n", - c->id, c_n, ch_n); - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -/** - * Functions to handle messages from clients - */ -static struct GNUNET_SERVER_MessageHandler client_handlers[] = { - {&handle_new_client, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT, 0}, - {&handle_channel_create, NULL, GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE, - sizeof (struct GNUNET_CADET_ChannelMessage)}, - {&handle_channel_destroy, NULL, GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY, - sizeof (struct GNUNET_CADET_ChannelMessage)}, - {&handle_data, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA, 0}, - {&handle_ack, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK, - sizeof (struct GNUNET_CADET_LocalAck)}, - {&handle_get_peers, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS, - sizeof (struct GNUNET_MessageHeader)}, - {&handle_get_tunnels, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS, - sizeof (struct GNUNET_MessageHeader)}, - {&handle_show_tunnel, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL, - sizeof (struct GNUNET_CADET_LocalInfo)}, - {NULL, NULL, 0, 0} -}; - - - -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ - -/** - * Initialize server subsystem. - * - * @param handle Server handle. - */ -void -GML_init (struct GNUNET_SERVER_Handle *handle) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); - server_handle = handle; - GNUNET_SERVER_suspend (server_handle); - ports = GNUNET_CONTAINER_multihashmap32_create (32); -} - - -/** - * Install server (service) handlers and start listening to clients. - */ -void -GML_start (void) -{ - GNUNET_SERVER_add_handlers (server_handle, client_handlers); - GNUNET_SERVER_connect_notify (server_handle, &handle_client_connect, NULL); - GNUNET_SERVER_disconnect_notify (server_handle, &handle_client_disconnect, - NULL); - nc = GNUNET_SERVER_notification_context_create (server_handle, 1); - - clients_head = NULL; - clients_tail = NULL; - next_client_id = 0; - GNUNET_SERVER_resume (server_handle); -} - - -/** - * Shutdown server. - */ -void -GML_shutdown (void) -{ - if (nc != NULL) - { - GNUNET_SERVER_notification_context_destroy (nc); - nc = NULL; - } -} - - -/** - * Get a channel from a client. - * - * @param c Client to check. - * @param chid Channel ID, must be local (> 0x800...). - * - * @return non-NULL if channel exists in the clients lists - */ -struct CadetChannel * -GML_channel_get (struct CadetClient *c, CADET_ChannelNumber chid) -{ - struct GNUNET_CONTAINER_MultiHashMap32 *map; - - if (0 == (chid & GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)) - { - GNUNET_break_op (0); - LOG (GNUNET_ERROR_TYPE_DEBUG, "CHID %X not a local chid\n", chid); - return NULL; - } - - if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV) - map = c->incoming_channels; - else if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) - map = c->own_channels; - else - { - GNUNET_break (0); - map = NULL; - } - if (NULL == map) - { - GNUNET_break (0); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Client %s does no t have a valid map for CHID %X\n", - GML_2s (c), chid); - return NULL; - } - return GNUNET_CONTAINER_multihashmap32_get (map, chid); -} - - -/** - * Add a channel to a client - * - * @param client Client. - * @param chid Channel ID. - * @param ch Channel. - */ -void -GML_channel_add (struct CadetClient *client, - uint32_t chid, - struct CadetChannel *ch) -{ - if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV) - GNUNET_CONTAINER_multihashmap32_put (client->incoming_channels, chid, ch, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); - else if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) - GNUNET_CONTAINER_multihashmap32_put (client->own_channels, chid, ch, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); - else - GNUNET_break (0); -} - - -/** - * Remove a channel from a client. - * - * @param client Client. - * @param chid Channel ID. - * @param ch Channel. - */ -void -GML_channel_remove (struct CadetClient *client, - uint32_t chid, - struct CadetChannel *ch) -{ - if (GNUNET_CADET_LOCAL_CHANNEL_ID_SERV <= chid) - GNUNET_break (GNUNET_YES == - GNUNET_CONTAINER_multihashmap32_remove (client->incoming_channels, - chid, ch)); - else if (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI <= chid) - GNUNET_break (GNUNET_YES == - GNUNET_CONTAINER_multihashmap32_remove (client->own_channels, - chid, ch)); - else - GNUNET_break (0); -} - - -/** - * Get the tunnel's next free local channel ID. - * - * @param c Client. - * - * @return LID of a channel free to use. - */ -CADET_ChannelNumber -GML_get_next_chid (struct CadetClient *c) -{ - CADET_ChannelNumber chid; - - while (NULL != GML_channel_get (c, c->next_chid)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %u exists...\n", c->next_chid); - c->next_chid = (c->next_chid + 1) | GNUNET_CADET_LOCAL_CHANNEL_ID_SERV; - } - chid = c->next_chid; - c->next_chid = (c->next_chid + 1) | GNUNET_CADET_LOCAL_CHANNEL_ID_SERV; - - return chid; -} - - -/** - * Check if client has registered with the service and has not disconnected - * - * @param client the client to check - * - * @return non-NULL if client exists in the global DLL - */ -struct CadetClient * -GML_client_get (struct GNUNET_SERVER_Client *client) -{ - return GNUNET_SERVER_client_get_user_context (client, struct CadetClient); -} - -/** - * Find a client that has opened a port - * - * @param port Port to check. - * - * @return non-NULL if a client has the port. - */ -struct CadetClient * -GML_client_get_by_port (uint32_t port) -{ - return GNUNET_CONTAINER_multihashmap32_get (ports, port); -} - - -/** - * Deletes a channel from a client (either owner or destination). - * - * @param c Client whose tunnel to delete. - * @param ch Channel which should be deleted. - * @param id Channel ID. - */ -void -GML_client_delete_channel (struct CadetClient *c, - struct CadetChannel *ch, - CADET_ChannelNumber id) -{ - int res; - - if (GNUNET_CADET_LOCAL_CHANNEL_ID_SERV <= id) - { - res = GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels, - id, ch); - if (GNUNET_YES != res) - LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_channel dest KO\n"); - } - else if (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI <= id) - { - res = GNUNET_CONTAINER_multihashmap32_remove (c->own_channels, - id, ch); - if (GNUNET_YES != res) - LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_tunnel root KO\n"); - } - else - { - GNUNET_break (0); - } -} - -/** - * Build a local ACK message and send it to a local client, if needed. - * - * If the client was already allowed to send data, do nothing. - * - * @param c Client to whom send the ACK. - * @param id Channel ID to use - */ -void -GML_send_ack (struct CadetClient *c, CADET_ChannelNumber id) -{ - struct GNUNET_CADET_LocalAck msg; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "send local %s ack on %X towards %p\n", - id < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV ? "FWD" : "BCK", id, c); - - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK); - msg.channel_id = htonl (id); - GNUNET_SERVER_notification_context_unicast (nc, - c->handle, - &msg.header, - GNUNET_NO); - -} - - - -/** - * Notify the client that a new incoming channel was created. - * - * @param c Client to notify. - * @param id Channel ID. - * @param port Channel's destination port. - * @param opt Options (bit array). - * @param peer Origin peer. - */ -void -GML_send_channel_create (struct CadetClient *c, - uint32_t id, uint32_t port, uint32_t opt, - const struct GNUNET_PeerIdentity *peer) -{ - struct GNUNET_CADET_ChannelMessage msg; - - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE); - msg.channel_id = htonl (id); - msg.port = htonl (port); - msg.opt = htonl (opt); - msg.peer = *peer; - GNUNET_SERVER_notification_context_unicast (nc, c->handle, - &msg.header, GNUNET_NO); -} - - -/** - * Build a local channel NACK message and send it to a local client. - * - * @param c Client to whom send the NACK. - * @param id Channel ID to use - */ -void -GML_send_channel_nack (struct CadetClient *c, CADET_ChannelNumber id) -{ - struct GNUNET_CADET_LocalAck msg; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "send local nack on %X towards %p\n", - id, c); - - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK); - msg.channel_id = htonl (id); - GNUNET_SERVER_notification_context_unicast (nc, - c->handle, - &msg.header, - GNUNET_NO); - -} - -/** - * Notify a client that a channel is no longer valid. - * - * @param c Client. - * @param id ID of the channel that is destroyed. - */ -void -GML_send_channel_destroy (struct CadetClient *c, uint32_t id) -{ - struct GNUNET_CADET_ChannelMessage msg; - - if (NULL == c) - { - GNUNET_break (0); - return; - } - if (GNUNET_YES == c->shutting_down) - return; - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY); - msg.channel_id = htonl (id); - msg.port = htonl (0); - memset (&msg.peer, 0, sizeof (msg.peer)); - msg.opt = htonl (0); - GNUNET_SERVER_notification_context_unicast (nc, c->handle, - &msg.header, GNUNET_NO); -} - - -/** - * Modify the cadet message ID from global to local and send to client. - * - * @param c Client to send to. - * @param msg Message to modify and send. - * @param id Channel ID to use (c can be both owner and client). - */ -void -GML_send_data (struct CadetClient *c, - const struct GNUNET_CADET_Data *msg, - CADET_ChannelNumber id) -{ - struct GNUNET_CADET_LocalData *copy; - uint16_t size = ntohs (msg->header.size) - sizeof (struct GNUNET_CADET_Data); - char cbuf[size + sizeof (struct GNUNET_CADET_LocalData)]; - - if (size < sizeof (struct GNUNET_MessageHeader)) - { - GNUNET_break_op (0); - return; - } - if (NULL == c) - { - GNUNET_break (0); - return; - } - copy = (struct GNUNET_CADET_LocalData *) cbuf; - memcpy (©[1], &msg[1], size); - copy->header.size = htons (sizeof (struct GNUNET_CADET_LocalData) + size); - copy->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA); - copy->id = htonl (id); - GNUNET_SERVER_notification_context_unicast (nc, c->handle, - ©->header, GNUNET_NO); -} - - -/** - * Get the static string to represent a client. - * - * @param c Client. - * - * @return Static string for the client. - */ -const char * -GML_2s (const struct CadetClient *c) -{ - static char buf[32]; - - sprintf (buf, "%u", c->id); - return buf; -} diff --git a/src/mesh/gnunet-service-cadet_local.h b/src/mesh/gnunet-service-cadet_local.h deleted file mode 100644 index b78b3c5da..000000000 --- a/src/mesh/gnunet-service-cadet_local.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2013 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 cadet/gnunet-service-cadet_local.h - * @brief cadet service; dealing with local clients - * @author Bartlomiej Polot - * - * All functions in this file should use the prefix GML (Gnunet Cadet Local) - */ - -#ifndef GNUNET_SERVICE_CADET_LOCAL_H -#define GNUNET_SERVICE_CADET_LOCAL_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "platform.h" -#include "gnunet_util_lib.h" - -/** - * Struct containing information about a client of the service - */ -struct CadetClient; - -#include "gnunet-service-cadet_channel.h" - -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ - -/** - * Initialize server subsystem. - * - * @param handle Server handle. - */ -void -GML_init (struct GNUNET_SERVER_Handle *handle); - -/** - * Install server (service) handlers and start listening to clients. - */ -void -GML_start (void); - -/** - * Shutdown server. - */ -void -GML_shutdown (void); - -/** - * Get a channel from a client. - * - * @param c Client to check. - * @param chid Channel ID, must be local (> 0x800...). - * - * @return non-NULL if channel exists in the clients lists - */ -struct CadetChannel * -GML_channel_get (struct CadetClient *c, uint32_t chid); - -/** - * Add a channel to a client - * - * @param client Client. - * @param chid Channel ID. - * @param ch Channel. - */ -void -GML_channel_add (struct CadetClient *client, - uint32_t chid, - struct CadetChannel *ch); - -/** - * Remove a channel from a client - * - * @param client Client. - * @param chid Channel ID. - * @param ch Channel. - */ -void -GML_channel_remove (struct CadetClient *client, - uint32_t chid, - struct CadetChannel *ch); - -/** - * Get the tunnel's next free local channel ID. - * - * @param c Client. - * - * @return LID of a channel free to use. - */ -CADET_ChannelNumber -GML_get_next_chid (struct CadetClient *c); - -/** - * Check if client has registered with the service and has not disconnected - * - * @param client the client to check - * - * @return non-NULL if client exists in the global DLL - */ -struct CadetClient * -GML_client_get (struct GNUNET_SERVER_Client *client); - -/** - * Find a client that has opened a port - * - * @param port Port to check. - * - * @return non-NULL if a client has the port. - */ -struct CadetClient * -GML_client_get_by_port (uint32_t port); - -/** - * Deletes a tunnel from a client (either owner or destination). - * - * @param c Client whose tunnel to delete. - * @param ch Channel which should be deleted. - * @param id Channel ID. - */ -void -GML_client_delete_channel (struct CadetClient *c, - struct CadetChannel *ch, - CADET_ChannelNumber id); - -/** - * Build a local ACK message and send it to a local client, if needed. - * - * If the client was already allowed to send data, do nothing. - * - * @param c Client to whom send the ACK. - * @param id Channel ID to use - */ -void -GML_send_ack (struct CadetClient *c, CADET_ChannelNumber id); - -/** - * Notify the appropriate client that a new incoming channel was created. - * - * @param c Client to notify. - * @param id Channel ID. - * @param port Channel's destination port. - * @param opt Options (bit array). - * @param peer Origin peer. - */ -void -GML_send_channel_create (struct CadetClient *c, - uint32_t id, uint32_t port, uint32_t opt, - const struct GNUNET_PeerIdentity *peer); - -/** - * Build a local channel NACK message and send it to a local client. - * - * @param c Client to whom send the NACK. - * @param id Channel ID to use - */ -void -GML_send_channel_nack (struct CadetClient *c, CADET_ChannelNumber id); - -/** - * Notify a client that a channel is no longer valid. - * - * @param c Client. - * @param id ID of the channel that is destroyed. - */ -void -GML_send_channel_destroy (struct CadetClient *c, uint32_t id); - -/** - * Modify the cadet message ID from global to local and send to client. - * - * @param c Client to send to. - * @param msg Message to modify and send. - * @param id Channel ID to use (c can be both owner and client). - */ -void -GML_send_data (struct CadetClient *c, - const struct GNUNET_CADET_Data *msg, - CADET_ChannelNumber id); - -/** - * Get the static string to represent a client. - * - * @param c Client. - * - * @return Static string for the client. - */ -const char * -GML_2s (const struct CadetClient *c); - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_CADET_SERVICE_LOCAL_H */ -#endif -/* end of gnunet-cadet-service_LOCAL.h */ diff --git a/src/mesh/gnunet-service-cadet_peer.c b/src/mesh/gnunet-service-cadet_peer.c deleted file mode 100644 index 287d42efe..000000000 --- a/src/mesh/gnunet-service-cadet_peer.c +++ /dev/null @@ -1,2219 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2013 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_util_lib.h" - -#include "gnunet_transport_service.h" -#include "gnunet_core_service.h" -#include "gnunet_statistics_service.h" - -#include "cadet_protocol.h" - -#include "gnunet-service-cadet_peer.h" -#include "gnunet-service-cadet_dht.h" -#include "gnunet-service-cadet_connection.h" -#include "gnunet-service-cadet_tunnel.h" -#include "cadet_path.h" - -#define LOG(level, ...) GNUNET_log_from (level,"cadet-p2p",__VA_ARGS__) - -/******************************************************************************/ -/******************************** STRUCTS **********************************/ -/******************************************************************************/ - -/** - * Struct containing info about a queued transmission to this peer - */ -struct CadetPeerQueue -{ - /** - * DLL next - */ - struct CadetPeerQueue *next; - - /** - * DLL previous - */ - struct CadetPeerQueue *prev; - - /** - * Peer this transmission is directed to. - */ - struct CadetPeer *peer; - - /** - * Connection this message belongs to. - */ - struct CadetConnection *c; - - /** - * Is FWD in c? - */ - int fwd; - - /** - * Pointer to info stucture used as cls. - */ - void *cls; - - /** - * Type of message - */ - uint16_t type; - - /** - * Type of message - */ - uint16_t payload_type; - - /** - * Type of message - */ - uint32_t payload_id; - - /** - * Size of the message - */ - size_t size; - - /** - * Set when this message starts waiting for CORE. - */ - struct GNUNET_TIME_Absolute start_waiting; - - /** - * Function to call on sending. - */ - GMP_sent callback; - - /** - * Closure for callback. - */ - void *callback_cls; -}; - -/** - * Struct containing all information regarding a given peer - */ -struct CadetPeer -{ - /** - * ID of the peer - */ - GNUNET_PEER_Id id; - - /** - * Last time we heard from this peer - */ - struct GNUNET_TIME_Absolute last_contact; - - /** - * Paths to reach the peer, ordered by ascending hop count - */ - struct CadetPeerPath *path_head; - - /** - * Paths to reach the peer, ordered by ascending hop count - */ - struct CadetPeerPath *path_tail; - - /** - * Handle to stop the DHT search for paths to this peer - */ - struct GMD_search_handle *search_h; - - /** - * Tunnel to this peer, if any. - */ - struct CadetTunnel3 *tunnel; - - /** - * Connections that go through this peer, indexed by tid; - */ - struct GNUNET_CONTAINER_MultiHashMap *connections; - - /** - * Handle for queued transmissions - */ - struct GNUNET_CORE_TransmitHandle *core_transmit; - - /** - * Transmission queue to core DLL head - */ - struct CadetPeerQueue *queue_head; - - /** - * Transmission queue to core DLL tail - */ - struct CadetPeerQueue *queue_tail; - - /** - * How many messages are in the queue to this peer. - */ - unsigned int queue_n; - - /** - * Hello message. - */ - struct GNUNET_HELLO_Message* hello; -}; - - -/******************************************************************************/ -/******************************* GLOBALS ***********************************/ -/******************************************************************************/ - -/** - * Global handle to the statistics service. - */ -extern struct GNUNET_STATISTICS_Handle *stats; - -/** - * Local peer own ID (full value). - */ -extern struct GNUNET_PeerIdentity my_full_id; - -/** - * Local peer own ID (short) - */ -extern GNUNET_PEER_Id myid; - -/** - * Peers known, indexed by PeerIdentity (CadetPeer). - */ -static struct GNUNET_CONTAINER_MultiPeerMap *peers; - -/** - * How many peers do we want to remember? - */ -static unsigned long long max_peers; - -/** - * Percentage of messages that will be dropped (for test purposes only). - */ -static unsigned long long drop_percent; - -/** - * Handle to communicate with core. - */ -static struct GNUNET_CORE_Handle *core_handle; - -/** - * Handle to try to start new connections. - */ -static struct GNUNET_TRANSPORT_Handle *transport_handle; - - -/******************************************************************************/ -/***************************** DEBUG *********************************/ -/******************************************************************************/ - -static void -queue_debug (struct CadetPeer *peer) -{ - struct CadetPeerQueue *q; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "QQQ Messages queued towards %s\n", GMP_2s (peer)); - LOG (GNUNET_ERROR_TYPE_DEBUG, "QQQ core tmt rdy: %p\n", peer->core_transmit); - - for (q = peer->queue_head; NULL != q; q = q->next) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "QQQ - %s %s on %s\n", - GM_m2s (q->type), GM_f2s (q->fwd), GMC_2s (q->c)); - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, "QQQ End queued towards %s\n", GMP_2s (peer)); -} - - -/******************************************************************************/ -/***************************** CORE HELPERS *********************************/ -/******************************************************************************/ - - -/** - * Iterator to notify all connections of a broken link. Mark connections - * to destroy after all traffic has been sent. - * - * @param cls Closure (peer disconnected). - * @param key Current key code (peer id). - * @param value Value in the hash map (connection). - * - * @return #GNUNET_YES to continue to iterate. - */ -static int -notify_broken (void *cls, - const struct GNUNET_HashCode *key, - void *value) -{ - struct CadetPeer *peer = cls; - struct CadetConnection *c = value; - - LOG (GNUNET_ERROR_TYPE_DEBUG, " notifying %s due to %s\n", - GMC_2s (c), GMP_2s (peer)); - GMC_notify_broken (c, peer); - - return GNUNET_YES; -} - - -/** - * Remove the direct path to the peer. - * - * @param peer Peer to remove the direct path from. - * - */ -static struct CadetPeerPath * -pop_direct_path (struct CadetPeer *peer) -{ - struct CadetPeerPath *iter; - - for (iter = peer->path_head; NULL != iter; iter = iter->next) - { - if (2 <= iter->length) - { - GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, iter); - return iter; - } - } - return NULL; -} - - -/******************************************************************************/ -/***************************** CORE CALLBACKS *********************************/ -/******************************************************************************/ - -/** - * Method called whenever a given peer connects. - * - * @param cls closure - * @param peer peer identity this notification is about - */ -static void -core_connect (void *cls, const struct GNUNET_PeerIdentity *peer) -{ - struct CadetPeer *mp; - struct CadetPeerPath *path; - char own_id[16]; - - strncpy (own_id, GNUNET_i2s (&my_full_id), 15); - mp = GMP_get (peer); - if (myid == mp->id) - { - LOG (GNUNET_ERROR_TYPE_INFO, "CONNECTED %s (self)\n", own_id); - path = path_new (1); - } - else - { - LOG (GNUNET_ERROR_TYPE_INFO, "CONNECTED %s <= %s\n", - own_id, GNUNET_i2s (peer)); - path = path_new (2); - path->peers[1] = mp->id; - GNUNET_PEER_change_rc (mp->id, 1); - GNUNET_STATISTICS_update (stats, "# peers", 1, GNUNET_NO); - } - path->peers[0] = myid; - GNUNET_PEER_change_rc (myid, 1); - GMP_add_path (mp, path, GNUNET_YES); - - mp->connections = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_YES); - - if (NULL != GMP_get_tunnel (mp) && - 0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, peer)) - { - GMP_connect (mp); - } - - return; -} - - -/** - * Method called whenever a peer disconnects. - * - * @param cls closure - * @param peer peer identity this notification is about - */ -static void -core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) -{ - struct CadetPeer *p; - struct CadetPeerPath *direct_path; - char own_id[16]; - - strncpy (own_id, GNUNET_i2s (&my_full_id), 15); - p = GNUNET_CONTAINER_multipeermap_get (peers, peer); - if (NULL == p) - { - GNUNET_break (0); - return; - } - if (myid == p->id) - LOG (GNUNET_ERROR_TYPE_INFO, "DISCONNECTED %s (self)\n", own_id); - else - LOG (GNUNET_ERROR_TYPE_DEBUG, "DISCONNECTED %s <= %s\n", - own_id, GNUNET_i2s (peer)); - direct_path = pop_direct_path (p); - GNUNET_CONTAINER_multihashmap_iterate (p->connections, ¬ify_broken, p); - GNUNET_CONTAINER_multihashmap_destroy (p->connections); - p->connections = NULL; - if (NULL != p->core_transmit) - { - GNUNET_CORE_notify_transmit_ready_cancel (p->core_transmit); - p->core_transmit = NULL; - } - GNUNET_STATISTICS_update (stats, "# peers", -1, GNUNET_NO); - - path_destroy (direct_path); - return; -} - - -/** - * Functions to handle messages from core - */ -static struct GNUNET_CORE_MessageHandler core_handlers[] = { - {&GMC_handle_create, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, 0}, - {&GMC_handle_confirm, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK, - sizeof (struct GNUNET_CADET_ConnectionACK)}, - {&GMC_handle_broken, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN, - sizeof (struct GNUNET_CADET_ConnectionBroken)}, - {&GMC_handle_destroy, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY, - sizeof (struct GNUNET_CADET_ConnectionDestroy)}, - {&GMC_handle_ack, GNUNET_MESSAGE_TYPE_CADET_ACK, - sizeof (struct GNUNET_CADET_ACK)}, - {&GMC_handle_poll, GNUNET_MESSAGE_TYPE_CADET_POLL, - sizeof (struct GNUNET_CADET_Poll)}, - {&GMC_handle_encrypted, GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED, 0}, - {&GMC_handle_kx, GNUNET_MESSAGE_TYPE_CADET_KX, 0}, - {NULL, 0, 0} -}; - - -/** - * To be called on core init/fail. - * - * @param cls Closure (config) - * @param identity the public identity of this peer - */ -static void -core_init (void *cls, - const struct GNUNET_PeerIdentity *identity) -{ - const struct GNUNET_CONFIGURATION_Handle *c = cls; - static int i = 0; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Core init\n"); - if (0 != memcmp (identity, &my_full_id, sizeof (my_full_id))) - { - LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong CORE service\n")); - LOG (GNUNET_ERROR_TYPE_ERROR, " core id %s\n", GNUNET_i2s (identity)); - LOG (GNUNET_ERROR_TYPE_ERROR, " my id %s\n", GNUNET_i2s (&my_full_id)); - GNUNET_CORE_disconnect (core_handle); - core_handle = GNUNET_CORE_connect (c, /* Main configuration */ - NULL, /* Closure passed to CADET functions */ - &core_init, /* Call core_init once connected */ - &core_connect, /* Handle connects */ - &core_disconnect, /* remove peers on disconnects */ - NULL, /* Don't notify about all incoming messages */ - GNUNET_NO, /* For header only in notification */ - NULL, /* Don't notify about all outbound messages */ - GNUNET_NO, /* For header-only out notification */ - core_handlers); /* Register these handlers */ - if (10 < i++) - GNUNET_abort(); - } - GML_start (); - return; -} - - -/** - * Core callback to write a pre-constructed data packet to core buffer - * - * @param cls Closure (CadetTransmissionDescriptor with data in "data" member). - * @param size Number of bytes available in buf. - * @param buf Where the to write the message. - * - * @return number of bytes written to buf - */ -static size_t -send_core_data_raw (void *cls, size_t size, void *buf) -{ - struct GNUNET_MessageHeader *msg = cls; - size_t total_size; - - GNUNET_assert (NULL != msg); - total_size = ntohs (msg->size); - - if (total_size > size) - { - GNUNET_break (0); - return 0; - } - memcpy (buf, msg, total_size); - GNUNET_free (cls); - return total_size; -} - - -/** - * Function to send a create connection message to a peer. - * - * @param c Connection to create. - * @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 -send_core_connection_create (struct CadetConnection *c, size_t size, void *buf) -{ - struct GNUNET_CADET_ConnectionCreate *msg; - struct GNUNET_PeerIdentity *peer_ptr; - const struct CadetPeerPath *p = GMC_get_path (c); - size_t size_needed; - int i; - - if (NULL == p) - return 0; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending CONNECTION CREATE...\n"); - size_needed = - sizeof (struct GNUNET_CADET_ConnectionCreate) + - p->length * sizeof (struct GNUNET_PeerIdentity); - - if (size < size_needed || NULL == buf) - { - GNUNET_break (0); - return 0; - } - msg = (struct GNUNET_CADET_ConnectionCreate *) buf; - msg->header.size = htons (size_needed); - msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE); - msg->cid = *GMC_get_id (c); - - peer_ptr = (struct GNUNET_PeerIdentity *) &msg[1]; - for (i = 0; i < p->length; i++) - { - GNUNET_PEER_resolve (p->peers[i], peer_ptr++); - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "CONNECTION CREATE (%u bytes long) sent!\n", - size_needed); - return size_needed; -} - - -/** - * Creates a path ack message in buf and frees all unused resources. - * - * @param c Connection to send an ACK on. - * @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 -send_core_connection_ack (struct CadetConnection *c, size_t size, void *buf) -{ - struct GNUNET_CADET_ConnectionACK *msg = buf; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending CONNECTION ACK...\n"); - if (sizeof (struct GNUNET_CADET_ConnectionACK) > size) - { - GNUNET_break (0); - return 0; - } - msg->header.size = htons (sizeof (struct GNUNET_CADET_ConnectionACK)); - msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK); - msg->cid = *GMC_get_id (c); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "CONNECTION ACK sent!\n"); - return sizeof (struct GNUNET_CADET_ConnectionACK); -} - - -/******************************************************************************/ -/******************************** STATIC ***********************************/ -/******************************************************************************/ - - -/** - * Get priority for a queued message. - * - * @param q Queued message - * - * @return CORE priority to use. - */ -static enum GNUNET_CORE_Priority -get_priority (struct CadetPeerQueue *q) -{ - enum GNUNET_CORE_Priority low; - enum GNUNET_CORE_Priority high; - - if (NULL == q) - { - GNUNET_break (0); - return GNUNET_CORE_PRIO_BACKGROUND; - } - - /* Relayed traffic has lower priority, our own traffic has higher */ - if (NULL == q->c || GNUNET_NO == GMC_is_origin (q->c, q->fwd)) - { - low = GNUNET_CORE_PRIO_BEST_EFFORT; - high = GNUNET_CORE_PRIO_URGENT; - } - else - { - low = GNUNET_CORE_PRIO_URGENT; - high = GNUNET_CORE_PRIO_CRITICAL_CONTROL; - } - - /* Bulky payload has lower priority, control traffic has higher. */ - if (GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED == q->type) - return low; - else - return high; -} - - -/** - * Iterator over tunnel hash map entries to destroy the tunnel during shutdown. - * - * @param cls closure - * @param key current key code - * @param value value in the hash map - * @return #GNUNET_YES if we should continue to iterate, - * #GNUNET_NO if not. - */ -static int -shutdown_tunnel (void *cls, - const struct GNUNET_PeerIdentity *key, - void *value) -{ - struct CadetPeer *p = value; - struct CadetTunnel3 *t = p->tunnel; - - if (NULL != t) - GMT_destroy (t); - return GNUNET_YES; -} - - -/** - * Destroy the peer_info and free any allocated resources linked to it - * - * @param peer The peer_info to destroy. - * - * @return GNUNET_OK on success - */ -static int -peer_destroy (struct CadetPeer *peer) -{ - struct GNUNET_PeerIdentity id; - struct CadetPeerPath *p; - struct CadetPeerPath *nextp; - - GNUNET_PEER_resolve (peer->id, &id); - GNUNET_PEER_change_rc (peer->id, -1); - - LOG (GNUNET_ERROR_TYPE_WARNING, "destroying peer %s\n", GNUNET_i2s (&id)); - - if (GNUNET_YES != - GNUNET_CONTAINER_multipeermap_remove (peers, &id, peer)) - { - GNUNET_break (0); - LOG (GNUNET_ERROR_TYPE_WARNING, " not in peermap!!\n"); - } - if (NULL != peer->search_h) - { - GMD_search_stop (peer->search_h); - } - p = peer->path_head; - while (NULL != p) - { - nextp = p->next; - GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, p); - path_destroy (p); - p = nextp; - } - GMT_destroy_empty (peer->tunnel); - GNUNET_free (peer); - return GNUNET_OK; -} - - -/** - * Returns if peer is used (has a tunnel or is neighbor). - * - * @param peer Peer to check. - * - * @return #GNUNET_YES if peer is in use. - */ -static int -peer_is_used (struct CadetPeer *peer) -{ - struct CadetPeerPath *p; - - if (NULL != peer->tunnel) - return GNUNET_YES; - - for (p = peer->path_head; NULL != p; p = p->next) - { - if (p->length < 3) - return GNUNET_YES; - } - return GNUNET_NO; -} - - -/** - * Iterator over all the peers to get the oldest timestamp. - * - * @param cls Closure (unsued). - * @param key ID of the peer. - * @param value Peer_Info of the peer. - */ -static int -peer_get_oldest (void *cls, - const struct GNUNET_PeerIdentity *key, - void *value) -{ - struct CadetPeer *p = value; - struct GNUNET_TIME_Absolute *abs = cls; - - /* Don't count active peers */ - if (GNUNET_YES == peer_is_used (p)) - return GNUNET_YES; - - if (abs->abs_value_us < p->last_contact.abs_value_us) - abs->abs_value_us = p->last_contact.abs_value_us; - - return GNUNET_YES; -} - - -/** - * Iterator over all the peers to remove the oldest entry. - * - * @param cls Closure (unsued). - * @param key ID of the peer. - * @param value Peer_Info of the peer. - */ -static int -peer_timeout (void *cls, - const struct GNUNET_PeerIdentity *key, - void *value) -{ - struct CadetPeer *p = value; - struct GNUNET_TIME_Absolute *abs = cls; - - LOG (GNUNET_ERROR_TYPE_WARNING, - "peer %s timeout\n", GNUNET_i2s (key)); - - if (p->last_contact.abs_value_us == abs->abs_value_us && - GNUNET_NO == peer_is_used (p)) - { - peer_destroy (p); - return GNUNET_NO; - } - return GNUNET_YES; -} - - -/** - * Delete oldest unused peer. - */ -static void -peer_delete_oldest (void) -{ - struct GNUNET_TIME_Absolute abs; - - abs = GNUNET_TIME_UNIT_FOREVER_ABS; - - GNUNET_CONTAINER_multipeermap_iterate (peers, - &peer_get_oldest, - &abs); - GNUNET_CONTAINER_multipeermap_iterate (peers, - &peer_timeout, - &abs); -} - - -/** - * Choose the best (yet unused) path towards a peer, - * considering the tunnel properties. - * - * @param peer The destination peer. - * - * @return Best current known path towards the peer, if any. - */ -static struct CadetPeerPath * -peer_get_best_path (const struct CadetPeer *peer) -{ - struct CadetPeerPath *best_p; - struct CadetPeerPath *p; - unsigned int best_cost; - unsigned int cost; - - best_cost = UINT_MAX; - best_p = NULL; - for (p = peer->path_head; NULL != p; p = p->next) - { - if (GNUNET_NO == path_is_valid (p)) - continue; /* Don't use invalid paths. */ - if (GNUNET_YES == GMT_is_path_used (peer->tunnel, p)) - continue; /* If path is already in use, skip it. */ - - if ((cost = GMT_get_path_cost (peer->tunnel, p)) < best_cost) - { - best_cost = cost; - best_p = p; - } - } - return best_p; -} - - -/** - * Is this queue element sendable? - * - * - All management traffic is always sendable. - * - For payload traffic, check the connection flow control. - * - * @param q Queue element to inspect. - * - * @return #GNUNET_YES if it is sendable, #GNUNET_NO otherwise. - */ -static int -queue_is_sendable (struct CadetPeerQueue *q) -{ - /* Is PID-independent? */ - switch (q->type) - { - case GNUNET_MESSAGE_TYPE_CADET_ACK: - case GNUNET_MESSAGE_TYPE_CADET_POLL: - case GNUNET_MESSAGE_TYPE_CADET_KX: - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE: - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK: - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY: - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN: - return GNUNET_YES; - - case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED: - break; - - default: - GNUNET_break (0); - } - - return GMC_is_sendable (q->c, q->fwd); -} - - -/** - * Get first sendable message. - * - * @param peer The destination peer. - * - * @return First transmittable message, if any. Otherwise, NULL. - */ -static struct CadetPeerQueue * -peer_get_first_message (const struct CadetPeer *peer) -{ - struct CadetPeerQueue *q; - - for (q = peer->queue_head; NULL != q; q = q->next) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking %p towards %s\n", q, GMC_2s (q->c)); - if (queue_is_sendable (q)) - return q; - } - - return NULL; -} - - -/** - * Function to process paths received for a new peer addition. The recorded - * paths form the initial tunnel, which can be optimized later. - * Called on each result obtained for the DHT search. - * - * @param cls closure - * @param path - */ -static void -search_handler (void *cls, const struct CadetPeerPath *path) -{ - struct CadetPeer *peer = cls; - unsigned int connection_count; - - GMP_add_path_to_all (path, GNUNET_NO); - - /* Count connections */ - connection_count = GMT_count_connections (peer->tunnel); - - /* If we already have 3 (or more (?!)) connections, it's enough */ - if (3 <= connection_count) - return; - - if (CADET_TUNNEL3_SEARCHING == GMT_get_cstate (peer->tunnel)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " ... connect!\n"); - GMP_connect (peer); - } - return; -} - - - -/** - * Core callback to write a queued packet to core buffer - * - * @param cls Closure (peer info). - * @param size Number of bytes available in buf. - * @param buf Where the to write the message. - * - * @return number of bytes written to buf - */ -static size_t -queue_send (void *cls, size_t size, void *buf) -{ - struct CadetPeer *peer = cls; - struct CadetConnection *c; - struct CadetPeerQueue *queue; - const struct GNUNET_PeerIdentity *dst_id; - size_t data_size; - uint32_t pid; - - pid = 0; - peer->core_transmit = NULL; - LOG (GNUNET_ERROR_TYPE_DEBUG, "Queue send towards %s (max %u)\n", - GMP_2s (peer), size); - - if (NULL == buf || 0 == size) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Buffer size 0.\n"); - return 0; - } - - /* Initialize */ - queue = peer_get_first_message (peer); - if (NULL == queue) - { - GNUNET_assert (0); /* Core tmt_rdy should've been canceled */ - return 0; - } - c = queue->c; - - dst_id = GNUNET_PEER_resolve2 (peer->id); - LOG (GNUNET_ERROR_TYPE_DEBUG, " on connection %s %s\n", - GMC_2s (c), GM_f2s(queue->fwd)); - /* Check if buffer size is enough for the message */ - if (queue->size > size) - { - LOG (GNUNET_ERROR_TYPE_WARNING, "not enough room (%u vs %u), reissue\n", - queue->size, size); - peer->core_transmit = - GNUNET_CORE_notify_transmit_ready (core_handle, - GNUNET_NO, get_priority (queue), - GNUNET_TIME_UNIT_FOREVER_REL, - dst_id, - queue->size, - &queue_send, - peer); - return 0; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " size %u ok\n", queue->size); - - /* Fill buf */ - switch (queue->type) - { - case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED: - pid = GMC_get_pid (queue->c, queue->fwd); - LOG (GNUNET_ERROR_TYPE_DEBUG, " payload ID %u\n", pid); - data_size = send_core_data_raw (queue->cls, size, buf); - ((struct GNUNET_CADET_Encrypted *) buf)->pid = htonl (pid); - break; - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY: - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN: - case GNUNET_MESSAGE_TYPE_CADET_KX: - case GNUNET_MESSAGE_TYPE_CADET_ACK: - case GNUNET_MESSAGE_TYPE_CADET_POLL: - LOG (GNUNET_ERROR_TYPE_DEBUG, " raw %s\n", GM_m2s (queue->type)); - data_size = send_core_data_raw (queue->cls, size, buf); - break; - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE: - LOG (GNUNET_ERROR_TYPE_DEBUG, " path create\n"); - if (GMC_is_origin (c, GNUNET_YES)) - data_size = send_core_connection_create (queue->c, size, buf); - else - data_size = send_core_data_raw (queue->cls, size, buf); - break; - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK: - LOG (GNUNET_ERROR_TYPE_DEBUG, " path ack\n"); - if (GMC_is_origin (c, GNUNET_NO) || - GMC_is_origin (c, GNUNET_YES)) - data_size = send_core_connection_ack (queue->c, size, buf); - else - data_size = send_core_data_raw (queue->cls, size, buf); - break; - case GNUNET_MESSAGE_TYPE_CADET_DATA: - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE: - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: - /* This should be encapsulted */ - GNUNET_break (0); - data_size = 0; - break; - default: - GNUNET_break (0); - LOG (GNUNET_ERROR_TYPE_WARNING, " type unknown: %u\n", queue->type); - data_size = 0; - } - - if (0 < drop_percent && - GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 101) < drop_percent) - { - LOG (GNUNET_ERROR_TYPE_WARNING, "DD %s on connection %s\n", - GM_m2s (queue->type), GMC_2s (c)); - data_size = 0; - } - else - { - LOG (GNUNET_ERROR_TYPE_INFO, - "snd %s (%s %u) on connection %s (%p) %s (size %u)\n", - GM_m2s (queue->type), GM_m2s (queue->payload_type), - queue->payload_type, GMC_2s (c), c, GM_f2s (queue->fwd), data_size); - } - - /* Free queue, but cls was freed by send_core_* */ - GMP_queue_destroy (queue, GNUNET_NO, GNUNET_YES, pid); - - /* If more data in queue, send next */ - queue = peer_get_first_message (peer); - if (NULL != queue) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " more data!\n"); - if (NULL == peer->core_transmit) - { - peer->core_transmit = - GNUNET_CORE_notify_transmit_ready (core_handle, - GNUNET_NO, get_priority (queue), - GNUNET_TIME_UNIT_FOREVER_REL, - dst_id, - queue->size, - &queue_send, - peer); - queue->start_waiting = GNUNET_TIME_absolute_get (); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "* tmt rdy called somewhere else\n"); - } -// GMC_start_poll (); FIXME needed? - } - else - { -// GMC_stop_poll(); FIXME needed? - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, " return %d\n", data_size); - queue_debug (peer); - return data_size; -} - - -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ - - -/** - * Free a transmission that was already queued with all resources - * associated to the request. - * - * @param queue Queue handler to cancel. - * @param clear_cls Is it necessary to free associated cls? - * @param sent Was it really sent? (Could have been canceled) - * @param pid PID, if relevant (was sent and was a payload message). - */ -void -GMP_queue_destroy (struct CadetPeerQueue *queue, int clear_cls, - int sent, uint32_t pid) -{ - struct CadetPeer *peer; - - peer = queue->peer; - - if (GNUNET_YES == clear_cls) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "queue destroy type %s\n", - GM_m2s (queue->type)); - switch (queue->type) - { - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY: - LOG (GNUNET_ERROR_TYPE_INFO, "destroying a DESTROY message\n"); - /* fall through */ - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK: - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE: - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN: - case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE: - case GNUNET_MESSAGE_TYPE_CADET_KX: - case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED: - case GNUNET_MESSAGE_TYPE_CADET_ACK: - case GNUNET_MESSAGE_TYPE_CADET_POLL: - GNUNET_free_non_null (queue->cls); - break; - - default: - GNUNET_break (0); - LOG (GNUNET_ERROR_TYPE_ERROR, " type %s unknown!\n", - GM_m2s (queue->type)); - } - } - GNUNET_CONTAINER_DLL_remove (peer->queue_head, peer->queue_tail, queue); - - if (queue->type != GNUNET_MESSAGE_TYPE_CADET_ACK && - queue->type != GNUNET_MESSAGE_TYPE_CADET_POLL) - { - peer->queue_n--; - } - - if (NULL != queue->callback) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " calling callback\n"); - queue->callback (queue->callback_cls, - queue->c, sent, queue->type, pid, - queue->fwd, queue->size, - GNUNET_TIME_absolute_get_duration (queue->start_waiting)); - } - - if (NULL == peer_get_first_message (peer) && NULL != peer->core_transmit) - { - GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit); - peer->core_transmit = NULL; - } - - GNUNET_free (queue); -} - - -/** - * @brief Queue and pass message to core when possible. - * - * @param peer Peer towards which to queue the message. - * @param cls Closure (@c type dependant). It will be used by queue_send to - * build the message to be sent if not already prebuilt. - * @param type Type of the message, 0 for a raw message. - * @param size Size of the message. - * @param c Connection this message belongs to (can be NULL). - * @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!) - * @param cont Continuation to be called once CORE has taken the message. - * @param cont_cls Closure for @c cont. - * - * @return Handle to cancel the message before it is sent. Once cont is called - * message has been sent and therefore the handle is no longer valid. - */ -struct CadetPeerQueue * -GMP_queue_add (struct CadetPeer *peer, void *cls, uint16_t type, - uint16_t payload_type, uint32_t payload_id, size_t size, - struct CadetConnection *c, int fwd, - GMP_sent cont, void *cont_cls) -{ - struct CadetPeerQueue *queue; - int priority; - int call_core; - - LOG (GNUNET_ERROR_TYPE_INFO, - "que %s (%s %u) on connection %s (%p) %s towards %s (size %u)\n", - GM_m2s (type), GM_m2s (payload_type), payload_id, - GMC_2s (c), c, GM_f2s (fwd), GMP_2s (peer), size); - - if (NULL == peer->connections) - { - /* We are not connected to this peer, ignore request. */ - LOG (GNUNET_ERROR_TYPE_WARNING, "%s not a neighbor\n", GMP_2s (peer)); - GNUNET_STATISTICS_update (stats, "# messages dropped due to wrong hop", 1, - GNUNET_NO); - return NULL; - } - - priority = 0; - - if (GNUNET_MESSAGE_TYPE_CADET_POLL == type || - GNUNET_MESSAGE_TYPE_CADET_ACK == type) - { - priority = 100; - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, "priority %d\n", priority); - - call_core = NULL == c ? GNUNET_YES : GMC_is_sendable (c, fwd); - queue = GNUNET_new (struct CadetPeerQueue); - queue->cls = cls; - queue->type = type; - queue->payload_type = payload_type; - queue->payload_id = payload_id; - queue->size = size; - queue->peer = peer; - queue->c = c; - queue->fwd = fwd; - queue->callback = cont; - queue->callback_cls = cont_cls; - if (100 > priority) - { - GNUNET_CONTAINER_DLL_insert_tail (peer->queue_head, peer->queue_tail, queue); - peer->queue_n++; - } - else - { - GNUNET_CONTAINER_DLL_insert (peer->queue_head, peer->queue_tail, queue); - call_core = GNUNET_YES; - } - - if (NULL == peer->core_transmit && GNUNET_YES == call_core) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "calling core tmt rdy towards %s for %u bytes\n", - GMP_2s (peer), size); - peer->core_transmit = - GNUNET_CORE_notify_transmit_ready (core_handle, - GNUNET_NO, get_priority (queue), - GNUNET_TIME_UNIT_FOREVER_REL, - GNUNET_PEER_resolve2 (peer->id), - size, - &queue_send, - peer); - queue->start_waiting = GNUNET_TIME_absolute_get (); - } - else if (GNUNET_NO == call_core) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "core tmt rdy towards %s not needed\n", - GMP_2s (peer)); - - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "core tmt rdy towards %s already called\n", - GMP_2s (peer)); - - } - queue_debug (peer); - return queue; -} - - -/** - * Cancel all queued messages to a peer that belong to a certain connection. - * - * @param peer Peer towards whom to cancel. - * @param c Connection whose queued messages to cancel. Might be destroyed by - * the sent continuation call. - */ -void -GMP_queue_cancel (struct CadetPeer *peer, struct CadetConnection *c) -{ - struct CadetPeerQueue *q; - struct CadetPeerQueue *next; - struct CadetPeerQueue *prev; - - for (q = peer->queue_head; NULL != q; q = next) - { - prev = q->prev; - if (q->c == c) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "GMP queue cancel %s\n", GM_m2s (q->type)); - if (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY != q->type) - { - q->c = NULL; - } - else - { - GMP_queue_destroy (q, GNUNET_YES, GNUNET_NO, 0); - } - - /* Get next from prev, q->next might be already freed: - * queue destroy -> callback -> GMC_destroy -> cancel_queues -> here - */ - if (NULL == prev) - next = peer->queue_head; - else - next = prev->next; - } - else - { - next = q->next; - } - } - if (NULL == peer->queue_head) - { - if (NULL != peer->core_transmit) - { - GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit); - peer->core_transmit = NULL; - } - } -} - - -/** - * Get the first transmittable message for a connection. - * - * @param peer Neighboring peer. - * @param c Connection. - * - * @return First transmittable message. - */ -static struct CadetPeerQueue * -connection_get_first_message (struct CadetPeer *peer, struct CadetConnection *c) -{ - struct CadetPeerQueue *q; - - for (q = peer->queue_head; NULL != q; q = q->next) - { - if (q->c != c) - continue; - if (queue_is_sendable (q)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " sendable!!\n"); - return q; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " not sendable\n"); - } - - return NULL; -} - - -/** - * Get the first message for a connection and unqueue it. - * - * @param peer Neighboring peer. - * @param c Connection. - * - * @return First message for this connection. - */ -struct GNUNET_MessageHeader * -GMP_connection_pop (struct CadetPeer *peer, struct CadetConnection *c) -{ - struct CadetPeerQueue *q; - struct CadetPeerQueue *next; - struct GNUNET_MessageHeader *msg; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection pop on %s\n", GMC_2s (c)); - for (q = peer->queue_head; NULL != q; q = next) - { - next = q->next; - if (q->c != c) - continue; - switch (q->type) - { - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE: - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK: - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY: - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN: - case GNUNET_MESSAGE_TYPE_CADET_ACK: - case GNUNET_MESSAGE_TYPE_CADET_POLL: - GMP_queue_destroy (q, GNUNET_YES, GNUNET_NO, 0); - continue; - - case GNUNET_MESSAGE_TYPE_CADET_KX: - case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED: - msg = (struct GNUNET_MessageHeader *) q->cls; - GMP_queue_destroy (q, GNUNET_NO, GNUNET_NO, 0); - return msg; - - default: - GNUNET_break (0); - } - } - - return NULL; -} - - -void -GMP_queue_unlock (struct CadetPeer *peer, struct CadetConnection *c) -{ - struct CadetPeerQueue *q; - size_t size; - - if (NULL != peer->core_transmit) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " already unlocked!\n"); - return; /* Already unlocked */ - } - - q = connection_get_first_message (peer, c); - if (NULL == q) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " queue empty!\n"); - return; /* Nothing to transmit */ - } - - size = q->size; - peer->core_transmit = - GNUNET_CORE_notify_transmit_ready (core_handle, - GNUNET_NO, get_priority (q), - GNUNET_TIME_UNIT_FOREVER_REL, - GNUNET_PEER_resolve2 (peer->id), - size, - &queue_send, - peer); -} - - -/** - * Initialize the peer subsystem. - * - * @param c Configuration. - */ -void -GMP_init (const struct GNUNET_CONFIGURATION_Handle *c) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); - peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO); - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_PEERS", - &max_peers)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, - "CADET", "MAX_PEERS", "USING DEFAULT"); - max_peers = 1000; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (c, "CADET", "DROP_PERCENT", - &drop_percent)) - { - drop_percent = 0; - } - else - { - LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n"); - LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n"); - LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n"); - LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n"); - LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n"); - } - - core_handle = GNUNET_CORE_connect (c, /* Main configuration */ - NULL, /* Closure passed to CADET functions */ - &core_init, /* Call core_init once connected */ - &core_connect, /* Handle connects */ - &core_disconnect, /* remove peers on disconnects */ - NULL, /* Don't notify about all incoming messages */ - GNUNET_NO, /* For header only in notification */ - NULL, /* Don't notify about all outbound messages */ - GNUNET_NO, /* For header-only out notification */ - core_handlers); /* Register these handlers */ - if (GNUNET_YES != - GNUNET_CONFIGURATION_get_value_yesno (c, "CADET", "DISABLE_TRY_CONNECT")) - { - transport_handle = GNUNET_TRANSPORT_connect (c, &my_full_id, NULL, /* cls */ - /* Notify callbacks */ - NULL, NULL, NULL); - } - else - { - LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n"); - LOG (GNUNET_ERROR_TYPE_WARNING, "* DISABLE TRYING CONNECT in config *\n"); - LOG (GNUNET_ERROR_TYPE_WARNING, "* Use this only for test purposes. *\n"); - LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n"); - transport_handle = NULL; - } - - - - if (NULL == core_handle) - { - GNUNET_break (0); - GNUNET_SCHEDULER_shutdown (); - return; - } - -} - -/** - * Shut down the peer subsystem. - */ -void -GMP_shutdown (void) -{ - GNUNET_CONTAINER_multipeermap_iterate (peers, &shutdown_tunnel, NULL); - - if (core_handle != NULL) - { - GNUNET_CORE_disconnect (core_handle); - core_handle = NULL; - } - if (transport_handle != NULL) - { - GNUNET_TRANSPORT_disconnect (transport_handle); - transport_handle = NULL; - } - GNUNET_PEER_change_rc (myid, -1); -} - -/** - * Retrieve the CadetPeer stucture associated with the peer, create one - * and insert it in the appropriate structures if the peer is not known yet. - * - * @param peer_id Full identity of the peer. - * - * @return Existing or newly created peer structure. - */ -struct CadetPeer * -GMP_get (const struct GNUNET_PeerIdentity *peer_id) -{ - struct CadetPeer *peer; - - peer = GNUNET_CONTAINER_multipeermap_get (peers, peer_id); - if (NULL == peer) - { - peer = GNUNET_new (struct CadetPeer); - if (GNUNET_CONTAINER_multipeermap_size (peers) > max_peers) - { - peer_delete_oldest (); - } - GNUNET_CONTAINER_multipeermap_put (peers, peer_id, peer, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - peer->id = GNUNET_PEER_intern (peer_id); - } - peer->last_contact = GNUNET_TIME_absolute_get(); - - return peer; -} - - -/** - * Retrieve the CadetPeer stucture associated with the peer, create one - * and insert it in the appropriate structures if the peer is not known yet. - * - * @param peer Short identity of the peer. - * - * @return Existing or newly created peer structure. - */ -struct CadetPeer * -GMP_get_short (const GNUNET_PEER_Id peer) -{ - return GMP_get (GNUNET_PEER_resolve2 (peer)); -} - - -/** - * Try to connect to a peer on transport level. - * - * @param cls Closure (peer). - * @param tc TaskContext. - */ -static void -try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct CadetPeer *peer = cls; - - if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) - return; - - GNUNET_TRANSPORT_try_connect (transport_handle, - GNUNET_PEER_resolve2 (peer->id), NULL, NULL); -} - - -/** - * Try to establish a new connection to this peer (in its tunnel). - * If the peer doesn't have any path to it yet, try to get one. - * If the peer already has some path, send a CREATE CONNECTION towards it. - * - * @param peer Peer to connect to. - */ -void -GMP_connect (struct CadetPeer *peer) -{ - struct CadetTunnel3 *t; - struct CadetPeerPath *p; - struct CadetConnection *c; - int rerun_search; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "peer_connect towards %s\n", GMP_2s (peer)); - - /* If we have a current hello, try to connect using it. */ - GMP_try_connect (peer); - - t = peer->tunnel; - c = NULL; - rerun_search = GNUNET_NO; - - if (NULL != peer->path_head) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " some path exists\n"); - p = peer_get_best_path (peer); - if (NULL != p) - { - char *s; - - s = path_2s (p); - LOG (GNUNET_ERROR_TYPE_DEBUG, " path to use: %s\n", s); - GNUNET_free (s); - - c = GMT_use_path (t, p); - if (NULL == c) - { - /* This case can happen when the path includes a first hop that is - * not yet known to be connected. - * - * This happens quite often during testing when running cadet - * under valgrind: core connect notifications come very late and the - * DHT result has already come and created a valid path. - * In this case, the peer->connections hashmap will be NULL and - * tunnel_use_path will not be able to create a connection from that - * path. - * - * Re-running the DHT GET should give core time to callback. - * - * GMT_use_path -> GMC_new -> register_neighbors takes care of - * updating statistics about this issue. - */ - rerun_search = GNUNET_YES; - } - else - { - GMC_send_create (c); - return; - } - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " but is NULL, all paths are in use\n"); - } - } - - if (NULL != peer->search_h && GNUNET_YES == rerun_search) - { - GMD_search_stop (peer->search_h); - peer->search_h = NULL; - LOG (GNUNET_ERROR_TYPE_DEBUG, - " Stopping DHT GET for peer %s\n", - GMP_2s (peer)); - } - - if (NULL == peer->search_h) - { - const struct GNUNET_PeerIdentity *id; - - id = GNUNET_PEER_resolve2 (peer->id); - LOG (GNUNET_ERROR_TYPE_DEBUG, - " Starting DHT GET for peer %s\n", GMP_2s (peer)); - peer->search_h = GMD_search (id, &search_handler, peer); - if (CADET_TUNNEL3_NEW == GMT_get_cstate (t)) - GMT_change_cstate (t, CADET_TUNNEL3_SEARCHING); - } -} - - -/** - * Chech whether there is a direct (core level) connection to peer. - * - * @param peer Peer to check. - * - * @return #GNUNET_YES if there is a direct connection. - */ -int -GMP_is_neighbor (const struct CadetPeer *peer) -{ - struct CadetPeerPath *path; - - if (NULL == peer->connections) - return GNUNET_NO; - - for (path = peer->path_head; NULL != path; path = path->next) - { - if (3 > path->length) - return GNUNET_YES; - } - - /* Is not a neighbor but connections is not NULL, probably disconnecting */ - return GNUNET_NO; -} - - -/** - * Create and initialize a new tunnel towards a peer, in case it has none. - * In case the peer already has a tunnel, nothing is done. - * - * Does not generate any traffic, just creates the local data structures. - * - * @param peer Peer towards which to create the tunnel. - */ -void -GMP_add_tunnel (struct CadetPeer *peer) -{ - if (NULL != peer->tunnel) - return; - peer->tunnel = GMT_new (peer); -} - - -/** - * Add a connection to a neighboring peer. - * - * Store that the peer is the first hop of the connection in one - * direction and that on peer disconnect the connection must be - * notified and destroyed, for it will no longer be valid. - * - * @param peer Peer to add connection to. - * @param c Connection to add. - * - * @return GNUNET_OK on success. - */ -int -GMP_add_connection (struct CadetPeer *peer, - struct CadetConnection *c) -{ - int result; - LOG (GNUNET_ERROR_TYPE_DEBUG, "adding connection %s\n", GMC_2s (c)); - LOG (GNUNET_ERROR_TYPE_DEBUG, "to peer %s\n", GMP_2s (peer)); - - if (NULL == peer->connections) - { - GNUNET_break (0); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Peer %s is not a neighbor!\n", - GMP_2s (peer)); - return GNUNET_SYSERR; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, - "peer %s ok, has %u connections.\n", - GMP_2s (peer), GNUNET_CONTAINER_multihashmap_size (peer->connections)); - result = GNUNET_CONTAINER_multihashmap_put (peer->connections, - GMC_get_h (c), - c, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - LOG (GNUNET_ERROR_TYPE_DEBUG, - " now has %u connections.\n", - GNUNET_CONTAINER_multihashmap_size (peer->connections)); - LOG (GNUNET_ERROR_TYPE_DEBUG, "result %u\n", result); - - return result; -} - - -/** - * Add the path to the peer and update the path used to reach it in case this - * is the shortest. - * - * @param peer Destination peer to add the path to. - * @param path New path to add. Last peer must be the peer in arg 1. - * Path will be either used of freed if already known. - * @param trusted Do we trust that this path is real? - * - * @return path if path was taken, pointer to existing duplicate if exists - * NULL on error. - */ -struct CadetPeerPath * -GMP_add_path (struct CadetPeer *peer, struct CadetPeerPath *path, - int trusted) -{ - struct CadetPeerPath *aux; - unsigned int l; - unsigned int l2; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "adding path [%u] to peer %s\n", - path->length, GMP_2s (peer)); - - if ((NULL == peer) || (NULL == path)) - { - GNUNET_break (0); - path_destroy (path); - return NULL; - } - if (path->peers[path->length - 1] != peer->id) - { - GNUNET_break (0); - path_destroy (path); - return NULL; - } - - for (l = 1; l < path->length; l++) - { - if (path->peers[l] == myid) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " shortening path by %u\n", l); - for (l2 = 0; l2 < path->length - l; l2++) - { - path->peers[l2] = path->peers[l + l2]; - } - path->length -= l; - l = 1; - path->peers = GNUNET_realloc (path->peers, - path->length * sizeof (GNUNET_PEER_Id)); - } - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, " final length: %u\n", path->length); - - if (2 >= path->length && GNUNET_NO == trusted) - { - /* Only allow CORE to tell us about direct paths */ - path_destroy (path); - return NULL; - } - - l = path_get_length (path); - if (0 == l) - { - path_destroy (path); - return NULL; - } - - GNUNET_assert (peer->id == path->peers[path->length - 1]); - for (aux = peer->path_head; aux != NULL; aux = aux->next) - { - l2 = path_get_length (aux); - if (l2 > l) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " added\n"); - GNUNET_CONTAINER_DLL_insert_before (peer->path_head, - peer->path_tail, aux, path); - if (NULL != peer->tunnel && 3 < GMT_count_connections (peer->tunnel)) - { - GMP_connect (peer); - } - return path; - } - else - { - if (l2 == l && memcmp (path->peers, aux->peers, l) == 0) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " already known\n"); - path_destroy (path); - return aux; - } - } - } - GNUNET_CONTAINER_DLL_insert_tail (peer->path_head, peer->path_tail, - path); - LOG (GNUNET_ERROR_TYPE_DEBUG, " added last\n"); - if (NULL != peer->tunnel && 3 < GMT_count_connections (peer->tunnel)) - { - GMP_connect (peer); - } - return path; -} - - -/** - * Add the path to the origin peer and update the path used to reach it in case - * this is the shortest. - * The path is given in peer_info -> destination, therefore we turn the path - * upside down first. - * - * @param peer Peer to add the path to, being the origin of the path. - * @param path New path to add after being inversed. - * Path will be either used or freed. - * @param trusted Do we trust that this path is real? - * - * @return path if path was taken, pointer to existing duplicate if exists - * NULL on error. - */ -struct CadetPeerPath * -GMP_add_path_to_origin (struct CadetPeer *peer, - struct CadetPeerPath *path, - int trusted) -{ - if (NULL == path) - return NULL; - path_invert (path); - return GMP_add_path (peer, path, trusted); -} - - -/** - * Adds a path to the info of all the peers in the path - * - * @param p Path to process. - * @param confirmed Whether we know if the path works or not. - */ -void -GMP_add_path_to_all (const struct CadetPeerPath *p, int confirmed) -{ - unsigned int i; - - /* TODO: invert and add */ - for (i = 0; i < p->length && p->peers[i] != myid; i++) /* skip'em */ ; - for (i++; i < p->length; i++) - { - struct CadetPeer *aux; - struct CadetPeerPath *copy; - - aux = GMP_get_short (p->peers[i]); - copy = path_duplicate (p); - copy->length = i + 1; - GMP_add_path (aux, copy, p->length < 3 ? GNUNET_NO : confirmed); - } -} - - -/** - * Remove any path to the peer that has the extact same peers as the one given. - * - * @param peer Peer to remove the path from. - * @param path Path to remove. Is always destroyed . - */ -void -GMP_remove_path (struct CadetPeer *peer, struct CadetPeerPath *path) -{ - struct CadetPeerPath *iter; - struct CadetPeerPath *next; - - GNUNET_assert (myid == path->peers[0]); - GNUNET_assert (peer->id == path->peers[path->length - 1]); - - for (iter = peer->path_head; NULL != iter; iter = next) - { - next = iter->next; - if (0 == memcmp (path->peers, iter->peers, - sizeof (GNUNET_PEER_Id) * path->length)) - { - GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, iter); - if (iter != path) - path_destroy (iter); - } - } - path_destroy (path); -} - - -/** - * Remove a connection from a neighboring peer. - * - * @param peer Peer to remove connection from. - * @param c Connection to remove. - * - * @return GNUNET_OK on success. - */ -int -GMP_remove_connection (struct CadetPeer *peer, - const struct CadetConnection *c) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "removing connection %s\n", GMC_2s (c)); - LOG (GNUNET_ERROR_TYPE_DEBUG, "from peer %s\n", GMP_2s (peer)); - - if (NULL == peer || NULL == peer->connections) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Peer %s is not a neighbor!\n", - GMP_2s (peer)); - return GNUNET_SYSERR; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, - "peer %s ok, has %u connections.\n", - GMP_2s (peer), GNUNET_CONTAINER_multihashmap_size (peer->connections)); - - return GNUNET_CONTAINER_multihashmap_remove (peer->connections, - GMC_get_h (c), - c); -} - -/** - * Start the DHT search for new paths towards the peer: we don't have - * enough good connections. - * - * @param peer Destination peer. - */ -void -GMP_start_search (struct CadetPeer *peer) -{ - if (NULL != peer->search_h) - { - GNUNET_break (0); - return; - } - - peer->search_h = GMD_search (GMP_get_id (peer), &search_handler, peer); -} - - -/** - * Stop the DHT search for new paths towards the peer: we already have - * enough good connections. - * - * @param peer Destination peer. - */ -void -GMP_stop_search (struct CadetPeer *peer) -{ - if (NULL == peer->search_h) - { - return; - } - - GMD_search_stop (peer->search_h); - peer->search_h = NULL; -} - - -/** - * Get the Full ID of a peer. - * - * @param peer Peer to get from. - * - * @return Full ID of peer. - */ -const struct GNUNET_PeerIdentity * -GMP_get_id (const struct CadetPeer *peer) -{ - return GNUNET_PEER_resolve2 (peer->id); -} - - -/** - * Get the Short ID of a peer. - * - * @param peer Peer to get from. - * - * @return Short ID of peer. - */ -GNUNET_PEER_Id -GMP_get_short_id (const struct CadetPeer *peer) -{ - return peer->id; -} - - -/** - * Set tunnel. - * - * @param peer Peer. - * @param t Tunnel. - */ -void -GMP_set_tunnel (struct CadetPeer *peer, struct CadetTunnel3 *t) -{ - peer->tunnel = t; - if (NULL == t && NULL != peer->search_h) - { - GMP_stop_search (peer); - } -} - - -/** - * Get the tunnel towards a peer. - * - * @param peer Peer to get from. - * - * @return Tunnel towards peer. - */ -struct CadetTunnel3 * -GMP_get_tunnel (const struct CadetPeer *peer) -{ - return peer->tunnel; -} - - -/** - * Set the hello message. - * - * @param peer Peer whose message to set. - * @param hello Hello message. - */ -void -GMP_set_hello (struct CadetPeer *peer, const struct GNUNET_HELLO_Message *hello) -{ - struct GNUNET_HELLO_Message *old; - size_t size; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "set hello for %s\n", GMP_2s (peer)); - if (NULL == hello) - return; - - old = GMP_get_hello (peer); - if (NULL == old) - { - size = GNUNET_HELLO_size (hello); - LOG (GNUNET_ERROR_TYPE_DEBUG, " new (%u bytes)\n", size); - peer->hello = GNUNET_malloc (size); - memcpy (peer->hello, hello, size); - } - else - { - peer->hello = GNUNET_HELLO_merge (old, hello); - LOG (GNUNET_ERROR_TYPE_DEBUG, " merge into %p (%u bytes)\n", - peer->hello, GNUNET_HELLO_size (hello)); - GNUNET_free (old); - } -} - - -/** - * Get the hello message. - * - * @param peer Peer whose message to get. - * - * @return Hello message. - */ -struct GNUNET_HELLO_Message * -GMP_get_hello (struct CadetPeer *peer) -{ - struct GNUNET_TIME_Absolute expiration; - struct GNUNET_TIME_Relative remaining; - - if (NULL == peer->hello) - return NULL; - - expiration = GNUNET_HELLO_get_last_expiration (peer->hello); - remaining = GNUNET_TIME_absolute_get_remaining (expiration); - if (0 == remaining.rel_value_us) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " get - hello expired on %s\n", - GNUNET_STRINGS_absolute_time_to_string (expiration)); - GNUNET_free (peer->hello); - peer->hello = NULL; - } - return peer->hello; -} - - -/** - * Try to connect to a peer on TRANSPORT level. - * - * @param peer Peer to whom to connect. - */ -void -GMP_try_connect (struct CadetPeer *peer) -{ - struct GNUNET_HELLO_Message *hello; - struct GNUNET_MessageHeader *mh; - - if (NULL == transport_handle) - return; - - hello = GMP_get_hello (peer); - if (NULL == hello) - return; - - mh = GNUNET_HELLO_get_header (hello); - GNUNET_TRANSPORT_offer_hello (transport_handle, mh, try_connect, peer); -} - - -/** - * Notify a peer that a link between two other peers is broken. If any path - * used that link, eliminate it. - * - * @param peer Peer affected by the change. - * @param peer1 Peer whose link is broken. - * @param peer2 Peer whose link is broken. - */ -void -GMP_notify_broken_link (struct CadetPeer *peer, - struct GNUNET_PeerIdentity *peer1, - struct GNUNET_PeerIdentity *peer2) -{ - struct CadetPeerPath *iter; - struct CadetPeerPath *next; - unsigned int i; - GNUNET_PEER_Id p1; - GNUNET_PEER_Id p2; - - p1 = GNUNET_PEER_search (peer1); - p2 = GNUNET_PEER_search (peer2); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Link %u-%u broken\n", p1, p2); - if (0 == p1 || 0 == p2) - { - /* We don't even know them */ - return; - } - - for (iter = peer->path_head; NULL != iter; iter = next) - { - next = iter->next; - for (i = 0; i < iter->length - 1; i++) - { - if ((iter->peers[i] == p1 && iter->peers[i + 1] == p2) - || (iter->peers[i] == p2 && iter->peers[i + 1] == p1)) - { - char *s; - - s = path_2s (iter); - LOG (GNUNET_ERROR_TYPE_DEBUG, " - invalidating %s\n", s); - GNUNET_free (s); - - path_invalidate (iter); - } - } - } -} - - -/** - * Count the number of known paths toward the peer. - * - * @param peer Peer to get path info. - * - * @return Number of known paths. - */ -unsigned int -GMP_count_paths (const struct CadetPeer *peer) -{ - struct CadetPeerPath *iter; - unsigned int i; - - for (iter = peer->path_head, i = 0; NULL != iter; iter = iter->next) - i++; - - return i; -} - - -/** - * Iterate all known peers. - * - * @param iter Iterator. - * @param cls Closure for @c iter. - */ -void -GMP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls) -{ - GNUNET_CONTAINER_multipeermap_iterate (peers, iter, cls); -} - - -/** - * Get the static string for a peer ID. - * - * @param peer Peer. - * - * @return Static string for it's ID. - */ -const char * -GMP_2s (const struct CadetPeer *peer) -{ - if (NULL == peer) - return "(NULL)"; - return GNUNET_i2s (GNUNET_PEER_resolve2 (peer->id)); -} diff --git a/src/mesh/gnunet-service-cadet_peer.h b/src/mesh/gnunet-service-cadet_peer.h deleted file mode 100644 index 9f1146e9f..000000000 --- a/src/mesh/gnunet-service-cadet_peer.h +++ /dev/null @@ -1,418 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2013 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 cadet/gnunet-service-cadet_peer.h - * @brief cadet service; dealing with remote peers - * @author Bartlomiej Polot - * - * All functions in this file should use the prefix GMP (Gnunet Cadet Peer) - */ - -#ifndef GNUNET_SERVICE_CADET_PEER_H -#define GNUNET_SERVICE_CADET_PEER_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "platform.h" -#include "gnunet_util_lib.h" - -/** - * Struct containing all information regarding a given peer - */ -struct CadetPeer; - -/** - * Struct containing info about a queued transmission to this peer - */ -struct CadetPeerQueue; - -#include "gnunet-service-cadet_connection.h" - -/** - * Callback called when a queued message is sent. - * - * @param cls Closure. - * @param c Connection this message was on. - * @param sent Was it really sent? (Could have been canceled) - * @param type Type of message sent. - * @param pid Packet ID, or 0 if not applicable (create, destroy, etc). - * @param fwd Was this a FWD going message? - * @param size Size of the message. - * @param wait Time spent waiting for core (only the time for THIS message) - */ -typedef void (*GMP_sent) (void *cls, - struct CadetConnection *c, int sent, - uint16_t type, uint32_t pid, int fwd, size_t size, - struct GNUNET_TIME_Relative wait); - -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ - -/** - * Initialize peer subsystem. - * - * @param c Configuration. - */ -void -GMP_init (const struct GNUNET_CONFIGURATION_Handle *c); - -/** - * Shut down the peer subsystem. - */ -void -GMP_shutdown (void); - - -/** - * Retrieve the CadetPeer stucture associated with the peer, create one - * and insert it in the appropriate structures if the peer is not known yet. - * - * @param peer_id Full identity of the peer. - * - * @return Existing or newly created peer structure. - */ -struct CadetPeer * -GMP_get (const struct GNUNET_PeerIdentity *peer_id); - - -/** - * Retrieve the CadetPeer stucture associated with the peer, create one - * and insert it in the appropriate structures if the peer is not known yet. - * - * @param peer Short identity of the peer. - * - * @return Existing or newly created peer structure. - */ -struct CadetPeer * -GMP_get_short (const GNUNET_PEER_Id peer); - -/** - * Try to establish a new connection to this peer (in its tunnel). - * If the peer doesn't have any path to it yet, try to get one. - * If the peer already has some path, send a CREATE CONNECTION towards it. - * - * @param peer Peer to connect to. - */ -void -GMP_connect (struct CadetPeer *peer); - -/** - * Free a transmission that was already queued with all resources - * associated to the request. - * - * @param queue Queue handler to cancel. - * @param clear_cls Is it necessary to free associated cls? - * @param sent Was it really sent? (Could have been canceled) - * @param pid PID, if relevant (was sent and was a payload message). - */ -void -GMP_queue_destroy (struct CadetPeerQueue *queue, int clear_cls, - int sent, uint32_t pid); - -/** - * @brief Queue and pass message to core when possible. - * - * @param peer Peer towards which to queue the message. - * @param cls Closure (@c type dependant). It will be used by queue_send to - * build the message to be sent if not already prebuilt. - * @param type Type of the message, 0 for a raw message. - * @param size Size of the message. - * @param c Connection this message belongs to (cannot be NULL). - * @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!) - * @param cont Continuation to be called once CORE has taken the message. - * @param cont_cls Closure for @c cont. - * - * @return Handle to cancel the message before it is sent. Once cont is called - * message has been sent and therefore the handle is no longer valid. - */ -struct CadetPeerQueue * -GMP_queue_add (struct CadetPeer *peer, void *cls, uint16_t type, - uint16_t payload_type, uint32_t payload_id, - size_t size, struct CadetConnection *c, int fwd, - GMP_sent cont, void *cont_cls); - -/** - * Cancel all queued messages to a peer that belong to a certain connection. - * - * @param peer Peer towards whom to cancel. - * @param c Connection whose queued messages to cancel. Might be destroyed by - * the sent continuation call. - */ -void -GMP_queue_cancel (struct CadetPeer *peer, struct CadetConnection *c); - -/** - * Get the first message for a connection and unqueue it. - * - * @param peer Neighboring peer. - * @param c Connection. - * - * @return First message for this connection. - */ -struct GNUNET_MessageHeader * -GMP_connection_pop (struct CadetPeer *peer, struct CadetConnection *c); - -void -GMP_queue_unlock (struct CadetPeer *peer, struct CadetConnection *c); - -/** - * Set tunnel. - * - * @param peer Peer. - * @param t Tunnel. - */ -void -GMP_set_tunnel (struct CadetPeer *peer, struct CadetTunnel3 *t); - -/** - * Check whether there is a direct (core level) connection to peer. - * - * @param peer Peer to check. - * - * @return #GNUNET_YES if there is a direct connection. - */ -int -GMP_is_neighbor (const struct CadetPeer *peer); - -/** - * Create and initialize a new tunnel towards a peer, in case it has none. - * - * Does not generate any traffic, just creates the local data structures. - * - * @param peer Peer towards which to create the tunnel. - */ -void -GMP_add_tunnel (struct CadetPeer *peer); - -/** - * Add a connection to a neighboring peer. - * - * Store that the peer is the first hop of the connection in one - * direction and that on peer disconnect the connection must be - * notified and destroyed, for it will no longer be valid. - * - * @param peer Peer to add connection to. - * @param c Connection to add. - * - * @return GNUNET_OK on success. - */ -int -GMP_add_connection (struct CadetPeer *peer, struct CadetConnection *c); - -/** - * Add the path to the peer and update the path used to reach it in case this - * is the shortest. - * - * @param peer Destination peer to add the path to. - * @param path New path to add. Last peer must be the peer in arg 1. - * Path will be either used of freed if already known. - * @param trusted Do we trust that this path is real? - * - * @return path if path was taken, pointer to existing duplicate if exists - * NULL on error. - */ -struct CadetPeerPath * -GMP_add_path (struct CadetPeer *peer, struct CadetPeerPath *p, int trusted); - -/** - * Add the path to the origin peer and update the path used to reach it in case - * this is the shortest. - * The path is given in peer_info -> destination, therefore we turn the path - * upside down first. - * - * @param peer Peer to add the path to, being the origin of the path. - * @param path New path to add after being inversed. - * Path will be either used or freed. - * @param trusted Do we trust that this path is real? - * - * @return path if path was taken, pointer to existing duplicate if exists - * NULL on error. - */ -struct CadetPeerPath * -GMP_add_path_to_origin (struct CadetPeer *peer, - struct CadetPeerPath *path, - int trusted); - -/** - * Adds a path to the info of all the peers in the path - * - * @param p Path to process. - * @param confirmed Whether we know if the path works or not. - */ -void -GMP_add_path_to_all (const struct CadetPeerPath *p, int confirmed); - -/** - * Remove any path to the peer that has the extact same peers as the one given. - * - * @param peer Peer to remove the path from. - * @param path Path to remove. Is always destroyed . - */ -void -GMP_remove_path (struct CadetPeer *peer, struct CadetPeerPath *path); - -/** - * Remove a connection from a neighboring peer. - * - * @param peer Peer to remove connection from. - * @param c Connection to remove. - * - * @return GNUNET_OK on success. - */ -int -GMP_remove_connection (struct CadetPeer *peer, const struct CadetConnection *c); - -/** - * Start the DHT search for new paths towards the peer: we don't have - * enough good connections. - * - * @param peer Destination peer. - */ -void -GMP_start_search (struct CadetPeer *peer); - -/** - * Stop the DHT search for new paths towards the peer: we already have - * enough good connections. - * - * @param peer Destination peer. - */ -void -GMP_stop_search (struct CadetPeer *peer); - -/** - * Get the Full ID of a peer. - * - * @param peer Peer to get from. - * - * @return Full ID of peer. - */ -const struct GNUNET_PeerIdentity * -GMP_get_id (const struct CadetPeer *peer); - -/** - * Get the Short ID of a peer. - * - * @param peer Peer to get from. - * - * @return Short ID of peer. - */ -GNUNET_PEER_Id -GMP_get_short_id (const struct CadetPeer *peer); - -/** - * Get the tunnel towards a peer. - * - * @param peer Peer to get from. - * - * @return Tunnel towards peer. - */ -struct CadetTunnel3 * -GMP_get_tunnel (const struct CadetPeer *peer); - -/** - * Set the hello message. - * - * @param peer Peer whose message to set. - * @param hello Hello message. - */ -void -GMP_set_hello (struct CadetPeer *peer, const struct GNUNET_HELLO_Message *hello); - -/** - * Get the hello message. - * - * @param peer Peer whose message to get. - * - * @return Hello message. - */ -struct GNUNET_HELLO_Message * -GMP_get_hello (struct CadetPeer *peer); - - -/** - * Try to connect to a peer on TRANSPORT level. - * - * @param peer Peer to whom to connect. - */ -void -GMP_try_connect (struct CadetPeer *peer); - -/** - * Notify a peer that a link between two other peers is broken. If any path - * used that link, eliminate it. - * - * @param peer Peer affected by the change. - * @param peer1 Peer whose link is broken. - * @param peer2 Peer whose link is broken. - */ -void -GMP_notify_broken_link (struct CadetPeer *peer, - struct GNUNET_PeerIdentity *peer1, - struct GNUNET_PeerIdentity *peer2); - -/** - * Count the number of known paths toward the peer. - * - * @param peer Peer to get path info. - * - * @return Number of known paths. - */ -unsigned int -GMP_count_paths (const struct CadetPeer *peer); - -/** - * Iterate all known peers. - * - * @param iter Iterator. - * @param cls Closure for @c iter. - */ -void -GMP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls); - -/** - * Get the static string for a peer ID. - * - * @param peer Peer. - * - * @return Static string for it's ID. - */ -const char * -GMP_2s (const struct CadetPeer *peer); - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_CADET_SERVICE_PEER_H */ -#endif -/* end of gnunet-cadet-service_peer.h */ diff --git a/src/mesh/gnunet-service-cadet_tunnel.c b/src/mesh/gnunet-service-cadet_tunnel.c deleted file mode 100644 index f2be27bf5..000000000 --- a/src/mesh/gnunet-service-cadet_tunnel.c +++ /dev/null @@ -1,2887 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2013 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_util_lib.h" - -#include "gnunet_signatures.h" -#include "gnunet_statistics_service.h" - -#include "cadet_protocol.h" -#include "cadet_path.h" - -#include "gnunet-service-cadet_tunnel.h" -#include "gnunet-service-cadet_connection.h" -#include "gnunet-service-cadet_channel.h" -#include "gnunet-service-cadet_peer.h" - -#define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__) - -#define REKEY_WAIT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5) - -#define CONNECTIONS_PER_TUNNEL 3 - -/******************************************************************************/ -/******************************** STRUCTS **********************************/ -/******************************************************************************/ - -struct CadetTChannel -{ - struct CadetTChannel *next; - struct CadetTChannel *prev; - struct CadetChannel *ch; -}; - - -/** - * Connection list and metadata. - */ -struct CadetTConnection -{ - /** - * Next in DLL. - */ - struct CadetTConnection *next; - - /** - * Prev in DLL. - */ - struct CadetTConnection *prev; - - /** - * Connection handle. - */ - struct CadetConnection *c; - - /** - * Creation time, to keep oldest connection alive. - */ - struct GNUNET_TIME_Absolute created; - - /** - * Connection throughput, to keep fastest connection alive. - */ - uint32_t throughput; -}; - -/** - * Structure used during a Key eXchange. - */ -struct CadetTunnelKXCtx -{ - /** - * Decryption ("their") old key, for decrypting traffic sent by the - * other end before the key exchange started. - */ - struct GNUNET_CRYPTO_SymmetricSessionKey d_key_old; - - /** - * Challenge to send in a ping and expect in the pong. - */ - uint32_t challenge; -}; - -/** - * Struct containing all information regarding a tunnel to a peer. - */ -struct CadetTunnel3 -{ - /** - * Endpoint of the tunnel. - */ - struct CadetPeer *peer; - - /** - * State of the tunnel connectivity. - */ - enum CadetTunnel3CState cstate; - - /** - * State of the tunnel encryption. - */ - enum CadetTunnel3EState estate; - - /** - * Key eXchange context. - */ - struct CadetTunnelKXCtx *kx_ctx; - - /** - * Encryption ("our") key. - */ - struct GNUNET_CRYPTO_SymmetricSessionKey e_key; - - /** - * Decryption ("their") key. - */ - struct GNUNET_CRYPTO_SymmetricSessionKey d_key; - - /** - * Task to start the rekey process. - */ - GNUNET_SCHEDULER_TaskIdentifier rekey_task; - - /** - * Paths that are actively used to reach the destination peer. - */ - struct CadetTConnection *connection_head; - struct CadetTConnection *connection_tail; - - /** - * Next connection number. - */ - uint32_t next_cid; - - /** - * Channels inside this tunnel. - */ - struct CadetTChannel *channel_head; - struct CadetTChannel *channel_tail; - - /** - * Channel ID for the next created channel. - */ - CADET_ChannelNumber next_chid; - - /** - * Destroy flag: if true, destroy on last message. - */ - GNUNET_SCHEDULER_TaskIdentifier destroy_task; - - /** - * Queued messages, to transmit once tunnel gets connected. - */ - struct CadetTunnelDelayed *tq_head; - struct CadetTunnelDelayed *tq_tail; -}; - - -/** - * Struct used to save messages in a non-ready tunnel to send once connected. - */ -struct CadetTunnelDelayed -{ - /** - * DLL - */ - struct CadetTunnelDelayed *next; - struct CadetTunnelDelayed *prev; - - /** - * Tunnel. - */ - struct CadetTunnel3 *t; - - /** - * Tunnel queue given to the channel to cancel request. Update on send_queued. - */ - struct CadetTunnel3Queue *tq; - - /** - * Message to send. - */ - /* struct GNUNET_MessageHeader *msg; */ -}; - - -/** - * Handle for messages queued but not yet sent. - */ -struct CadetTunnel3Queue -{ - /** - * Connection queue handle, to cancel if necessary. - */ - struct CadetConnectionQueue *cq; - - /** - * Handle in case message hasn't been given to a connection yet. - */ - struct CadetTunnelDelayed *tqd; - - /** - * Continuation to call once sent. - */ - GMT_sent cont; - - /** - * Closure for @c cont. - */ - void *cont_cls; -}; - - -/******************************************************************************/ -/******************************* GLOBALS ***********************************/ -/******************************************************************************/ - -/** - * Global handle to the statistics service. - */ -extern struct GNUNET_STATISTICS_Handle *stats; - -/** - * Local peer own ID (memory efficient handle). - */ -extern GNUNET_PEER_Id myid; - -/** - * Local peer own ID (full value). - */ -extern struct GNUNET_PeerIdentity my_full_id; - - -/** - * Don't try to recover tunnels if shutting down. - */ -extern int shutting_down; - - -/** - * Set of all tunnels, in order to trigger a new exchange on rekey. - * Indexed by peer's ID. - */ -static struct GNUNET_CONTAINER_MultiPeerMap *tunnels; - -/** - * Default TTL for payload packets. - */ -static unsigned long long default_ttl; - -/** - * Own private key. - */ -const static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key; - -/** - * Own ephemeral private key. - */ -static struct GNUNET_CRYPTO_EcdhePrivateKey *my_ephemeral_key; - -/** - * Cached message used to perform a key exchange. - */ -static struct GNUNET_CADET_KX_Ephemeral kx_msg; - -/** - * Task to generate a new ephemeral key. - */ -static GNUNET_SCHEDULER_TaskIdentifier rekey_task; - -/** - * Rekey period. - */ -static struct GNUNET_TIME_Relative rekey_period; - -/******************************************************************************/ -/******************************** STATIC ***********************************/ -/******************************************************************************/ - -/** - * Get string description for tunnel connectivity state. - * - * @param cs Tunnel state. - * - * @return String representation. - */ -static const char * -cstate2s (enum CadetTunnel3CState cs) -{ - static char buf[128]; - - switch (cs) - { - case CADET_TUNNEL3_NEW: - return "CADET_TUNNEL3_NEW"; - case CADET_TUNNEL3_SEARCHING: - return "CADET_TUNNEL3_SEARCHING"; - case CADET_TUNNEL3_WAITING: - return "CADET_TUNNEL3_WAITING"; - case CADET_TUNNEL3_READY: - return "CADET_TUNNEL3_READY"; - - default: - sprintf (buf, "%u (UNKNOWN STATE)", cs); - return buf; - } - return ""; -} - - -/** - * Get string description for tunnel encryption state. - * - * @param es Tunnel state. - * - * @return String representation. - */ -static const char * -estate2s (enum CadetTunnel3EState es) -{ - static char buf[128]; - - switch (es) - { - case CADET_TUNNEL3_KEY_UNINITIALIZED: - return "CADET_TUNNEL3_KEY_UNINITIALIZED"; - case CADET_TUNNEL3_KEY_SENT: - return "CADET_TUNNEL3_KEY_SENT"; - case CADET_TUNNEL3_KEY_PING: - return "CADET_TUNNEL3_KEY_PING"; - case CADET_TUNNEL3_KEY_OK: - return "CADET_TUNNEL3_KEY_OK"; - - default: - sprintf (buf, "%u (UNKNOWN STATE)", es); - return buf; - } - return ""; -} - - -/** - * @brief Check if tunnel is ready to send traffic. - * - * Tunnel must be connected and with encryption correctly set up. - * - * @param t Tunnel to check. - * - * @return #GNUNET_YES if ready, #GNUNET_NO otherwise - */ -static int -is_ready (struct CadetTunnel3 *t) -{ - int ready; - - GMT_debug (t); - ready = (CADET_TUNNEL3_READY == t->cstate && CADET_TUNNEL3_KEY_OK == t->estate); - ready = ready || GMT_is_loopback (t); - return ready; -} - - -/** - * Ephemeral key message purpose size. - * - * @return Size of the part of the ephemeral key message that must be signed. - */ -size_t -ephemeral_purpose_size (void) -{ - return sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + - sizeof (struct GNUNET_TIME_AbsoluteNBO) + - sizeof (struct GNUNET_TIME_AbsoluteNBO) + - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + - sizeof (struct GNUNET_PeerIdentity); -} - - -/** - * Size of the encrypted part of a ping message. - * - * @return Size of the encrypted part of a ping message. - */ -size_t -ping_encryption_size (void) -{ - return sizeof (struct GNUNET_PeerIdentity) + sizeof (uint32_t); -} - - -/** - * Get the channel's buffer. ONLY FOR NON-LOOPBACK CHANNELS!! - * - * @param tch Tunnel's channel handle. - * - * @return Amount of messages the channel can still buffer towards the client. - */ -static unsigned int -get_channel_buffer (const struct CadetTChannel *tch) -{ - int fwd; - - /* If channel is outgoing, is origin in the FWD direction and fwd is YES */ - fwd = GMCH_is_origin (tch->ch, GNUNET_YES); - - return GMCH_get_buffer (tch->ch, fwd); -} - - -/** - * Get the channel's allowance status. - * - * @param tch Tunnel's channel handle. - * - * @return #GNUNET_YES if we allowed the client to send data to us. - */ -static int -get_channel_allowed (const struct CadetTChannel *tch) -{ - int fwd; - - /* If channel is outgoing, is origin in the FWD direction and fwd is YES */ - fwd = GMCH_is_origin (tch->ch, GNUNET_YES); - - return GMCH_get_allowed (tch->ch, fwd); -} - - -/** - * Get the connection's buffer. - * - * @param tc Tunnel's connection handle. - * - * @return Amount of messages the connection can still buffer. - */ -static unsigned int -get_connection_buffer (const struct CadetTConnection *tc) -{ - int fwd; - - /* If connection is outgoing, is origin in the FWD direction and fwd is YES */ - fwd = GMC_is_origin (tc->c, GNUNET_YES); - - return GMC_get_buffer (tc->c, fwd); -} - - -/** - * Get the connection's allowance. - * - * @param tc Tunnel's connection handle. - * - * @return Amount of messages we have allowed the next peer to send us. - */ -static unsigned int -get_connection_allowed (const struct CadetTConnection *tc) -{ - int fwd; - - /* If connection is outgoing, is origin in the FWD direction and fwd is YES */ - fwd = GMC_is_origin (tc->c, GNUNET_YES); - - return GMC_get_allowed (tc->c, fwd); -} - - -/** - * Check that a ephemeral key message s well formed and correctly signed. - * - * @param t Tunnel on which the message came. - * @param msg The ephemeral key message. - * - * @return GNUNET_OK if message is fine, GNUNET_SYSERR otherwise. - */ -int -check_ephemeral (struct CadetTunnel3 *t, - const struct GNUNET_CADET_KX_Ephemeral *msg) -{ - /* Check message size */ - if (ntohs (msg->header.size) != sizeof (struct GNUNET_CADET_KX_Ephemeral)) - return GNUNET_SYSERR; - - /* Check signature size */ - if (ntohl (msg->purpose.size) != ephemeral_purpose_size ()) - return GNUNET_SYSERR; - - /* Check origin */ - if (0 != memcmp (&msg->origin_identity, - GMP_get_id (t->peer), - sizeof (struct GNUNET_PeerIdentity))) - return GNUNET_SYSERR; - - /* Check signature */ - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_CADET_KX, - &msg->purpose, - &msg->signature, - &msg->origin_identity.public_key)) - return GNUNET_SYSERR; - - return GNUNET_OK; -} - - -/** - * Encrypt data with the tunnel key. - * - * @param t Tunnel whose key to use. - * @param dst Destination for the encrypted data. - * @param src Source of the plaintext. Can overlap with @c dst. - * @param size Size of the plaintext. - * @param iv Initialization Vector to use. - */ -static int -t_encrypt (struct CadetTunnel3 *t, - void *dst, const void *src, - size_t size, uint32_t iv) -{ - struct GNUNET_CRYPTO_SymmetricInitializationVector siv; - size_t out_size; - - LOG (GNUNET_ERROR_TYPE_DEBUG, " t_encrypt start\n"); - GNUNET_CRYPTO_symmetric_derive_iv (&siv, &t->e_key, &iv, sizeof (iv), NULL); - LOG (GNUNET_ERROR_TYPE_DEBUG, " t_encrypt IV derived\n"); - out_size = GNUNET_CRYPTO_symmetric_encrypt (src, size, &t->e_key, &siv, dst); - LOG (GNUNET_ERROR_TYPE_DEBUG, " t_encrypt end\n"); - - return out_size; -} - - -/** - * Decrypt data with the tunnel key. - * - * @param t Tunnel whose key to use. - * @param dst Destination for the plaintext. - * @param src Source of the encrypted data. Can overlap with @c dst. - * @param size Size of the encrypted data. - * @param iv Initialization Vector to use. - */ -static int -t_decrypt (struct CadetTunnel3 *t, - void *dst, const void *src, - size_t size, uint32_t iv) -{ - struct GNUNET_CRYPTO_SymmetricInitializationVector siv; - struct GNUNET_CRYPTO_SymmetricSessionKey *key; - size_t out_size; - - LOG (GNUNET_ERROR_TYPE_DEBUG, " t_decrypt start\n"); - if (t->estate == CADET_TUNNEL3_KEY_OK || t->estate == CADET_TUNNEL3_KEY_PING) - { - key = &t->d_key; - } - else if (NULL != t->kx_ctx) - { - key = &t->kx_ctx->d_key_old; - } - else - { - GNUNET_STATISTICS_update (stats, "# non decryptable data", 1, GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "WARNING got data on %s without a valid key\n", - GMT_2s (t)); - GMT_debug (t); - return 0; - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, " t_decrypt iv\n"); - GNUNET_CRYPTO_symmetric_derive_iv (&siv, key, &iv, sizeof (iv), NULL); - LOG (GNUNET_ERROR_TYPE_DEBUG, " t_decrypt iv done\n"); - out_size = GNUNET_CRYPTO_symmetric_decrypt (src, size, key, &siv, dst); - LOG (GNUNET_ERROR_TYPE_DEBUG, " t_decrypt end\n"); - - return out_size; -} - - -/** - * Create key material by doing ECDH on the local and remote ephemeral keys. - * - * @param key_material Where to store the key material. - * @param ephemeral_key Peer's public ephemeral key. - */ -void -derive_key_material (struct GNUNET_HashCode *key_material, - const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key) -{ - if (GNUNET_OK != - GNUNET_CRYPTO_ecc_ecdh (my_ephemeral_key, - ephemeral_key, - key_material)) - { - GNUNET_break (0); - } -} - -/** - * Create a symmetic key from the identities of both ends and the key material - * from ECDH. - * - * @param key Destination for the generated key. - * @param sender ID of the peer that will encrypt with @c key. - * @param receiver ID of the peer that will decrypt with @c key. - * @param key_material Hash created with ECDH with the ephemeral keys. - */ -void -derive_symmertic (struct GNUNET_CRYPTO_SymmetricSessionKey *key, - const struct GNUNET_PeerIdentity *sender, - const struct GNUNET_PeerIdentity *receiver, - const struct GNUNET_HashCode *key_material) -{ - const char salt[] = "CADET kx salt"; - - GNUNET_CRYPTO_kdf (key, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey), - salt, sizeof (salt), - key_material, sizeof (struct GNUNET_HashCode), - sender, sizeof (struct GNUNET_PeerIdentity), - receiver, sizeof (struct GNUNET_PeerIdentity), - NULL); -} - -/** - * Pick a connection on which send the next data message. - * - * @param t Tunnel on which to send the message. - * - * @return The connection on which to send the next message. - */ -static struct CadetConnection * -tunnel_get_connection (struct CadetTunnel3 *t) -{ - struct CadetTConnection *iter; - struct CadetConnection *best; - unsigned int qn; - unsigned int lowest_q; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel_get_connection %s\n", GMT_2s (t)); - best = NULL; - lowest_q = UINT_MAX; - for (iter = t->connection_head; NULL != iter; iter = iter->next) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " connection %s: %u\n", - GMC_2s (iter->c), GMC_get_state (iter->c)); - if (CADET_CONNECTION_READY == GMC_get_state (iter->c)) - { - qn = GMC_get_qn (iter->c, GMC_is_origin (iter->c, GNUNET_YES)); - LOG (GNUNET_ERROR_TYPE_DEBUG, " q_n %u, \n", qn); - if (qn < lowest_q) - { - best = iter->c; - lowest_q = qn; - } - } - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " selected: connection %s\n", GMC_2s (best)); - return best; -} - - -/** - * Callback called when a queued message is sent. - * - * Calculates the average time and connection packet tracking. - * - * @param cls Closure (TunnelQueue handle). - * @param c Connection this message was on. - * @param q Connection queue handle (unused). - * @param type Type of message sent. - * @param fwd Was this a FWD going message? - * @param size Size of the message. - */ -static void -tun_message_sent (void *cls, - struct CadetConnection *c, - struct CadetConnectionQueue *q, - uint16_t type, int fwd, size_t size) -{ - struct CadetTunnel3Queue *qt = cls; - struct CadetTunnel3 *t; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "tun_message_sent\n"); - - GNUNET_assert (NULL != qt->cont); - t = NULL == c ? NULL : GMC_get_tunnel (c); - qt->cont (qt->cont_cls, t, qt, type, size); - GNUNET_free (qt); -} - - -/** - * Delete a queued message: either was sent or the channel was destroyed - * before the tunnel's key exchange had a chance to finish. - * - * @param tqd Delayed queue handle. - */ -static void -unqueue_data (struct CadetTunnelDelayed *tqd) -{ - GNUNET_CONTAINER_DLL_remove (tqd->t->tq_head, tqd->t->tq_tail, tqd); - GNUNET_free (tqd); -} - - -/** - * Cache a message to be sent once tunnel is online. - * - * @param t Tunnel to hold the message. - * @param msg Message itself (copy will be made). - */ -static struct CadetTunnelDelayed * -queue_data (struct CadetTunnel3 *t, const struct GNUNET_MessageHeader *msg) -{ - struct CadetTunnelDelayed *tqd; - uint16_t size = ntohs (msg->size); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "queue data on Tunnel %s\n", GMT_2s (t)); - - if (GNUNET_YES == is_ready (t)) - { - GNUNET_break (0); - return NULL; - } - - tqd = GNUNET_malloc (sizeof (struct CadetTunnelDelayed) + size); - - tqd->t = t; - memcpy (&tqd[1], msg, size); - GNUNET_CONTAINER_DLL_insert_tail (t->tq_head, t->tq_tail, tqd); - return tqd; -} - - -/** - * Calculate HMAC. - * - * @param t Tunnel to get keys from. - * @param plaintext Content to HMAC. - * @param size Size of @c plaintext. - * @param iv Initialization vector for the message. - * @param outgoing Is this an outgoing message that we encrypted? - * @param hmac Destination to store the HMAC. - */ -static void -t_hmac (struct CadetTunnel3 *t, const void *plaintext, size_t size, uint32_t iv, - int outgoing, struct GNUNET_CADET_Hash *hmac) -{ - struct GNUNET_CRYPTO_AuthKey auth_key; - static const char ctx[] = "cadet authentication key"; - struct GNUNET_CRYPTO_SymmetricSessionKey *key; - struct GNUNET_HashCode hash; - - key = outgoing ? &t->e_key : &t->d_key; - GNUNET_CRYPTO_hmac_derive_key (&auth_key, key, - &iv, sizeof (iv), - key, sizeof (*key), - ctx, sizeof (ctx), - NULL); - GNUNET_CRYPTO_hmac (&auth_key, plaintext, size, &hash); - memcpy (hmac, &hash, sizeof (*hmac)); -} - - -/** - * Sends an already built message on a tunnel, encrypting it and - * choosing the best connection. - * - * @param message Message to send. Function modifies it. - * @param t Tunnel on which this message is transmitted. - * @param c Connection to use (autoselect if NULL). - * @param force Force the tunnel to take the message (buffer overfill). - * @param cont Continuation to call once message is really sent. - * @param cont_cls Closure for @c cont. - * @param existing_q In case this a transmission of previously queued data, - * this should be TunnelQueue given to the client. - * Otherwise, NULL. - * - * @return Handle to cancel message. NULL if @c cont is NULL. - */ -static struct CadetTunnel3Queue * -send_prebuilt_message (const struct GNUNET_MessageHeader *message, - struct CadetTunnel3 *t, struct CadetConnection *c, - int force, GMT_sent cont, void *cont_cls, - struct CadetTunnel3Queue *existing_q) -{ - struct CadetTunnel3Queue *tq; - struct GNUNET_CADET_Encrypted *msg; - size_t size = ntohs (message->size); - char cbuf[sizeof (struct GNUNET_CADET_Encrypted) + size]; - uint32_t mid; - uint32_t iv; - uint16_t type; - int fwd; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT Send on Tunnel %s\n", GMT_2s (t)); - - if (GNUNET_NO == is_ready (t)) - { - struct CadetTunnelDelayed *tqd; - /* A non null existing_q indicates sending of queued data. - * Should only happen after tunnel becomes ready. - */ - GNUNET_assert (NULL == existing_q); - tqd = queue_data (t, message); - if (NULL == cont) - return NULL; - tq = GNUNET_new (struct CadetTunnel3Queue); - tq->tqd = tqd; - tqd->tq = tq; - tq->cont = cont; - tq->cont_cls = cont_cls; - return tq; - } - - GNUNET_assert (GNUNET_NO == GMT_is_loopback (t)); - - iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); - msg = (struct GNUNET_CADET_Encrypted *) cbuf; - msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED); - msg->iv = iv; - GNUNET_assert (t_encrypt (t, &msg[1], message, size, iv) == size); - t_hmac (t, &msg[1], size, iv, GNUNET_YES, &msg->hmac); - msg->header.size = htons (sizeof (struct GNUNET_CADET_Encrypted) + size); - - if (NULL == c) - c = tunnel_get_connection (t); - if (NULL == c) - { - if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task - || CADET_TUNNEL3_SEARCHING != t->cstate) - { - GNUNET_break (0); - GMT_debug (t); - } - return NULL; - } - - mid = 0; - type = ntohs (message->type); - switch (type) - { - case GNUNET_MESSAGE_TYPE_CADET_DATA: - case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK: - if (GNUNET_MESSAGE_TYPE_CADET_DATA == type) - mid = ntohl (((struct GNUNET_CADET_Data *) message)->mid); - else - mid = ntohl (((struct GNUNET_CADET_DataACK *) message)->mid); - /* Fall thru */ - case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE: - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE: - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK: - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK: - msg->cid = *GMC_get_id (c); - msg->ttl = htonl (default_ttl); - break; - default: - GNUNET_break (0); - } - LOG (GNUNET_ERROR_TYPE_DEBUG, "type %s\n", GM_m2s (type)); - - fwd = GMC_is_origin (c, GNUNET_YES); - - if (NULL == cont) - { - GNUNET_break (NULL == - GMC_send_prebuilt_message (&msg->header, type, mid, - c, fwd, force, NULL, NULL)); - return NULL; - } - if (NULL == existing_q) - { - tq = GNUNET_new (struct CadetTunnel3Queue); /* FIXME valgrind: leak*/ - } - else - { - tq = existing_q; - tq->tqd = NULL; - } - tq->cq = GMC_send_prebuilt_message (&msg->header, type, mid, c, fwd, force, - &tun_message_sent, tq); - tq->cont = cont; - tq->cont_cls = cont_cls; - - return tq; -} - - -/** - * Send all cached messages that we can, tunnel is online. - * - * @param t Tunnel that holds the messages. Cannot be loopback. - */ -static void -send_queued_data (struct CadetTunnel3 *t) -{ - struct CadetTunnelDelayed *tqd; - struct CadetTunnelDelayed *next; - unsigned int room; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "GMT_send_queued_data on tunnel %s\n", - GMT_2s (t)); - - if (GMT_is_loopback (t)) - { - GNUNET_break (0); - return; - } - - if (GNUNET_NO == is_ready (t)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " not ready yet: %s/%s\n", - estate2s (t->estate), cstate2s (t->cstate)); - return; - } - - room = GMT_get_connections_buffer (t); - LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space: %u\n", room); - LOG (GNUNET_ERROR_TYPE_DEBUG, " tq head: %p\n", t->tq_head); - for (tqd = t->tq_head; NULL != tqd && room > 0; tqd = next) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " sending queued data\n"); - next = tqd->next; - room--; - send_prebuilt_message ((struct GNUNET_MessageHeader *) &tqd[1], - tqd->t, NULL, GNUNET_YES, - NULL != tqd->tq ? tqd->tq->cont : NULL, - NULL != tqd->tq ? tqd->tq->cont_cls : NULL, - tqd->tq); - unqueue_data (tqd); - } - LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT_send_queued_data end\n", GMP_2s (t->peer)); -} - - -/** - * Sends key exchange message on a tunnel, choosing the best connection. - * Should not be called on loopback tunnels. - * - * @param t Tunnel on which this message is transmitted. - * @param message Message to send. Function modifies it. - */ -static void -send_kx (struct CadetTunnel3 *t, - const struct GNUNET_MessageHeader *message) -{ - struct CadetConnection *c; - struct GNUNET_CADET_KX *msg; - size_t size = ntohs (message->size); - char cbuf[sizeof (struct GNUNET_CADET_KX) + size]; - uint16_t type; - int fwd; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT KX on Tunnel %s\n", GMT_2s (t)); - - /* Avoid loopback. */ - if (GMT_is_loopback (t)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " loopback!\n"); - GNUNET_break (0); - return; - } - - if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " being destroyed, why bother\n"); - return; - } - - /* Must have a connection. */ - if (NULL == t->connection_head) - { - GNUNET_break (CADET_TUNNEL3_SEARCHING == t->cstate); - GMT_debug (t); - return; - } - - msg = (struct GNUNET_CADET_KX *) cbuf; - msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_KX); - msg->header.size = htons (sizeof (struct GNUNET_CADET_KX) + size); - c = tunnel_get_connection (t); - if (NULL == c) - { - GNUNET_break (GNUNET_SCHEDULER_NO_TASK != t->destroy_task - || CADET_TUNNEL3_READY != t->cstate); - GMT_debug (t); - return; - } - type = ntohs (message->type); - switch (type) - { - case GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL: - case GNUNET_MESSAGE_TYPE_CADET_KX_PING: - case GNUNET_MESSAGE_TYPE_CADET_KX_PONG: - memcpy (&msg[1], message, size); - break; - default: - LOG (GNUNET_ERROR_TYPE_DEBUG, "unkown type %s\n", - GM_m2s (type)); - GNUNET_break (0); - } - - fwd = GMC_is_origin (t->connection_head->c, GNUNET_YES); - /* TODO save handle and cancel in case of a unneeded retransmission */ - GMC_send_prebuilt_message (&msg->header, GNUNET_MESSAGE_TYPE_CADET_KX, - message->type, c, fwd, GNUNET_YES, NULL, NULL); -} - - -/** - * Send the ephemeral key on a tunnel. - * - * @param t Tunnel on which to send the key. - */ -static void -send_ephemeral (struct CadetTunnel3 *t) -{ - LOG (GNUNET_ERROR_TYPE_INFO, "=> EPHM for %s\n", GMT_2s (t)); - - kx_msg.sender_status = htonl (t->estate); - send_kx (t, &kx_msg.header); -} - -/** - * Send a ping message on a tunnel. - * - * @param t Tunnel on which to send the ping. - */ -static void -send_ping (struct CadetTunnel3 *t) -{ - struct GNUNET_CADET_KX_Ping msg; - - LOG (GNUNET_ERROR_TYPE_INFO, "=> PING for %s\n", GMT_2s (t)); - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_KX_PING); - msg.iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); - msg.target = *GMP_get_id (t->peer); - msg.nonce = t->kx_ctx->challenge; - - LOG (GNUNET_ERROR_TYPE_DEBUG, " sending %u\n", msg.nonce); - LOG (GNUNET_ERROR_TYPE_DEBUG, " towards %s\n", GNUNET_i2s (&msg.target)); - t_encrypt (t, &msg.target, &msg.target, ping_encryption_size(), msg.iv); - LOG (GNUNET_ERROR_TYPE_DEBUG, " e sending %u\n", msg.nonce); - LOG (GNUNET_ERROR_TYPE_DEBUG, " e towards %s\n", GNUNET_i2s (&msg.target)); - - send_kx (t, &msg.header); -} - - -/** - * Send a pong message on a tunnel. - * - * @param t Tunnel on which to send the pong. - * @param challenge Value sent in the ping that we have to send back. - */ -static void -send_pong (struct CadetTunnel3 *t, uint32_t challenge) -{ - struct GNUNET_CADET_KX_Pong msg; - - LOG (GNUNET_ERROR_TYPE_INFO, "=> PONG for %s\n", GMT_2s (t)); - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_KX_PONG); - msg.iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); - msg.nonce = challenge; - LOG (GNUNET_ERROR_TYPE_DEBUG, " sending %u\n", msg.nonce); - t_encrypt (t, &msg.nonce, &msg.nonce, sizeof (msg.nonce), msg.iv); - LOG (GNUNET_ERROR_TYPE_DEBUG, " e sending %u\n", msg.nonce); - - send_kx (t, &msg.header); -} - - -/** - * Initiate a rekey with the remote peer. - * - * @param cls Closure (tunnel). - * @param tc TaskContext. - */ -static void -rekey_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct CadetTunnel3 *t = cls; - - t->rekey_task = GNUNET_SCHEDULER_NO_TASK; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Re-key Tunnel %s\n", GMT_2s (t)); - if (NULL != tc && 0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) - return; - - if (NULL == t->kx_ctx) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " new kx ctx\n"); - t->kx_ctx = GNUNET_new (struct CadetTunnelKXCtx); - t->kx_ctx->challenge = - GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); - t->kx_ctx->d_key_old = t->d_key; - LOG (GNUNET_ERROR_TYPE_DEBUG, " new challenge for %s: %u\n", - GMT_2s (t), t->kx_ctx->challenge); - } - send_ephemeral (t); - switch (t->estate) - { - case CADET_TUNNEL3_KEY_UNINITIALIZED: - t->estate = CADET_TUNNEL3_KEY_SENT; - break; - case CADET_TUNNEL3_KEY_SENT: - break; - case CADET_TUNNEL3_KEY_PING: - case CADET_TUNNEL3_KEY_OK: - send_ping (t); - t->estate = CADET_TUNNEL3_KEY_PING; - break; - default: - LOG (GNUNET_ERROR_TYPE_DEBUG, "Unexpected state %u\n", t->estate); - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, " next call in %s\n", - GNUNET_STRINGS_relative_time_to_string (REKEY_WAIT, GNUNET_YES)); - t->rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_WAIT, &rekey_tunnel, t); -} - - -/** - * Out ephemeral key has changed, create new session key on all tunnels. - * - * @param cls Closure (size of the hashmap). - * @param key Current public key. - * @param value Value in the hash map (tunnel). - * - * @return #GNUNET_YES, so we should continue to iterate, - */ -static int -rekey_iterator (void *cls, - const struct GNUNET_PeerIdentity *key, - void *value) -{ - struct CadetTunnel3 *t = value; - struct GNUNET_TIME_Relative delay; - long n = (long) cls; - uint32_t r; - - if (GNUNET_SCHEDULER_NO_TASK != t->rekey_task) - return GNUNET_YES; - - if (GNUNET_YES == GMT_is_loopback (t)) - return GNUNET_YES; - - r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, (uint32_t) n * 100); - delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, r); - t->rekey_task = GNUNET_SCHEDULER_add_delayed (delay, &rekey_tunnel, t); - - return GNUNET_YES; -} - - -/** - * Create a new ephemeral key and key message, schedule next rekeying. - * - * @param cls Closure (unused). - * @param tc TaskContext. - */ -static void -rekey (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_TIME_Absolute time; - long n; - - rekey_task = GNUNET_SCHEDULER_NO_TASK; - - if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) - return; - - GNUNET_free_non_null (my_ephemeral_key); - my_ephemeral_key = GNUNET_CRYPTO_ecdhe_key_create (); - - time = GNUNET_TIME_absolute_get (); - kx_msg.creation_time = GNUNET_TIME_absolute_hton (time); - time = GNUNET_TIME_absolute_add (time, rekey_period); - time = GNUNET_TIME_absolute_add (time, GNUNET_TIME_UNIT_MINUTES); - kx_msg.expiration_time = GNUNET_TIME_absolute_hton (time); - GNUNET_CRYPTO_ecdhe_key_get_public (my_ephemeral_key, &kx_msg.ephemeral_key); - - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_eddsa_sign (my_private_key, - &kx_msg.purpose, - &kx_msg.signature)); - - n = (long) GNUNET_CONTAINER_multipeermap_size (tunnels); - GNUNET_CONTAINER_multipeermap_iterate (tunnels, &rekey_iterator, (void *) n); - - rekey_task = GNUNET_SCHEDULER_add_delayed (rekey_period, &rekey, NULL); -} - - -/** - * Called only on shutdown, destroy every tunnel. - * - * @param cls Closure (unused). - * @param key Current public key. - * @param value Value in the hash map (tunnel). - * - * @return #GNUNET_YES, so we should continue to iterate, - */ -static int -destroy_iterator (void *cls, - const struct GNUNET_PeerIdentity *key, - void *value) -{ - struct CadetTunnel3 *t = value; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT_shutdown destroying tunnel at %p\n", t); - GMT_destroy (t); - return GNUNET_YES; -} - - -/** - * Notify remote peer that we don't know a channel he is talking about, - * probably CHANNEL_DESTROY was missed. - * - * @param t Tunnel on which to notify. - * @param gid ID of the channel. - */ -static void -send_channel_destroy (struct CadetTunnel3 *t, unsigned int gid) -{ - struct GNUNET_CADET_ChannelManage msg; - - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY); - msg.header.size = htons (sizeof (msg)); - msg.chid = htonl (gid); - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "WARNING destroying unknown channel %u on tunnel %s\n", - gid, GMT_2s (t)); - send_prebuilt_message (&msg.header, t, NULL, GNUNET_YES, NULL, NULL, NULL); -} - - -/** - * Demultiplex data per channel and call appropriate channel handler. - * - * @param t Tunnel on which the data came. - * @param msg Data message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -static void -handle_data (struct CadetTunnel3 *t, - const struct GNUNET_CADET_Data *msg, - int fwd) -{ - struct CadetChannel *ch; - size_t size; - - /* Check size */ - size = ntohs (msg->header.size); - if (size < - sizeof (struct GNUNET_CADET_Data) + - sizeof (struct GNUNET_MessageHeader)) - { - GNUNET_break (0); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " payload of type %s\n", - GM_m2s (ntohs (msg[1].header.type))); - - /* Check channel */ - ch = GMT_get_channel (t, ntohl (msg->chid)); - if (NULL == ch) - { - GNUNET_STATISTICS_update (stats, "# data on unknown channel", - 1, GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel 0x%X unknown\n", - ntohl (msg->chid)); - send_channel_destroy (t, ntohl (msg->chid)); - return; - } - - GMCH_handle_data (ch, msg, fwd); -} - - -/** - * Demultiplex data ACKs per channel and update appropriate channel buffer info. - * - * @param t Tunnel on which the DATA ACK came. - * @param msg DATA ACK message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -static void -handle_data_ack (struct CadetTunnel3 *t, - const struct GNUNET_CADET_DataACK *msg, - int fwd) -{ - struct CadetChannel *ch; - size_t size; - - /* Check size */ - size = ntohs (msg->header.size); - if (size != sizeof (struct GNUNET_CADET_DataACK)) - { - GNUNET_break (0); - return; - } - - /* Check channel */ - ch = GMT_get_channel (t, ntohl (msg->chid)); - if (NULL == ch) - { - GNUNET_STATISTICS_update (stats, "# data ack on unknown channel", - 1, GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n", - ntohl (msg->chid)); - return; - } - - GMCH_handle_data_ack (ch, msg, fwd); -} - - -/** - * Handle channel create. - * - * @param t Tunnel on which the data came. - * @param msg Data message. - */ -static void -handle_ch_create (struct CadetTunnel3 *t, - const struct GNUNET_CADET_ChannelCreate *msg) -{ - struct CadetChannel *ch; - size_t size; - - /* Check size */ - size = ntohs (msg->header.size); - if (size != sizeof (struct GNUNET_CADET_ChannelCreate)) - { - GNUNET_break (0); - return; - } - - /* Check channel */ - ch = GMT_get_channel (t, ntohl (msg->chid)); - if (NULL != ch && ! GMT_is_loopback (t)) - { - /* Probably a retransmission, safe to ignore */ - LOG (GNUNET_ERROR_TYPE_DEBUG, " already exists...\n"); - } - ch = GMCH_handle_create (t, msg); - if (NULL != ch) - GMT_add_channel (t, ch); -} - - - -/** - * Handle channel NACK: check correctness and call channel handler for NACKs. - * - * @param t Tunnel on which the NACK came. - * @param msg NACK message. - */ -static void -handle_ch_nack (struct CadetTunnel3 *t, - const struct GNUNET_CADET_ChannelManage *msg) -{ - struct CadetChannel *ch; - size_t size; - - /* Check size */ - size = ntohs (msg->header.size); - if (size != sizeof (struct GNUNET_CADET_ChannelManage)) - { - GNUNET_break (0); - return; - } - - /* Check channel */ - ch = GMT_get_channel (t, ntohl (msg->chid)); - if (NULL == ch) - { - GNUNET_STATISTICS_update (stats, "# channel NACK on unknown channel", - 1, GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n", - ntohl (msg->chid)); - return; - } - - GMCH_handle_nack (ch); -} - - -/** - * Handle a CHANNEL ACK (SYNACK/ACK). - * - * @param t Tunnel on which the CHANNEL ACK came. - * @param msg CHANNEL ACK message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -static void -handle_ch_ack (struct CadetTunnel3 *t, - const struct GNUNET_CADET_ChannelManage *msg, - int fwd) -{ - struct CadetChannel *ch; - size_t size; - - /* Check size */ - size = ntohs (msg->header.size); - if (size != sizeof (struct GNUNET_CADET_ChannelManage)) - { - GNUNET_break (0); - return; - } - - /* Check channel */ - ch = GMT_get_channel (t, ntohl (msg->chid)); - if (NULL == ch) - { - GNUNET_STATISTICS_update (stats, "# channel ack on unknown channel", - 1, GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n", - ntohl (msg->chid)); - return; - } - - GMCH_handle_ack (ch, msg, fwd); -} - - - -/** - * Handle a channel destruction message. - * - * @param t Tunnel on which the message came. - * @param msg Channel destroy message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -static void -handle_ch_destroy (struct CadetTunnel3 *t, - const struct GNUNET_CADET_ChannelManage *msg, - int fwd) -{ - struct CadetChannel *ch; - size_t size; - - /* Check size */ - size = ntohs (msg->header.size); - if (size != sizeof (struct GNUNET_CADET_ChannelManage)) - { - GNUNET_break (0); - return; - } - - /* Check channel */ - ch = GMT_get_channel (t, ntohl (msg->chid)); - if (NULL == ch) - { - /* Probably a retransmission, safe to ignore */ - return; - } - - GMCH_handle_destroy (ch, msg, fwd); -} - - -/** - * The peer's ephemeral key has changed: update the symmetrical keys. - * - * @param t Tunnel this message came on. - * @param msg Key eXchange message. - */ -static void -handle_ephemeral (struct CadetTunnel3 *t, - const struct GNUNET_CADET_KX_Ephemeral *msg) -{ - struct GNUNET_HashCode km; - LOG (GNUNET_ERROR_TYPE_INFO, "<=== EPHM for %s\n", GMT_2s (t)); - - if (GNUNET_OK != check_ephemeral (t, msg)) - { - GNUNET_break_op (0); - return; - } - derive_key_material (&km, &msg->ephemeral_key); - LOG (GNUNET_ERROR_TYPE_DEBUG, " km is %s\n", GNUNET_h2s (&km)); - derive_symmertic (&t->e_key, &my_full_id, GMP_get_id (t->peer), &km); - derive_symmertic (&t->d_key, GMP_get_id (t->peer), &my_full_id, &km); - if (CADET_TUNNEL3_KEY_SENT == t->estate) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " our key was sent, send ping\n"); - send_ping (t); - t->estate = CADET_TUNNEL3_KEY_PING; - } -} - - -/** - * Peer wants to check our symmetrical keys by sending an encrypted challenge. - * Answer with by retransmitting the challenge with the "opposite" key. - * - * @param t Tunnel this message came on. - * @param msg Key eXchange Ping message. - */ -static void -handle_ping (struct CadetTunnel3 *t, - const struct GNUNET_CADET_KX_Ping *msg) -{ - struct GNUNET_CADET_KX_Ping res; - - if (ntohs (msg->header.size) != sizeof (res)) - { - GNUNET_break_op (0); - return; - } - - LOG (GNUNET_ERROR_TYPE_INFO, "<=== PING for %s\n", GMT_2s (t)); - t_decrypt (t, &res.target, &msg->target, ping_encryption_size (), msg->iv); - if (0 != memcmp (&my_full_id, &res.target, sizeof (my_full_id))) - { - // FIXME: move to debug - GNUNET_STATISTICS_update (stats, "# malformed PINGs", 1, GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_WARNING, " malformed PING on %s\n", GMT_2s (t)); - LOG (GNUNET_ERROR_TYPE_WARNING, " e got %u\n", msg->nonce); - LOG (GNUNET_ERROR_TYPE_WARNING, " e towards %s\n", GNUNET_i2s (&msg->target)); - LOG (GNUNET_ERROR_TYPE_WARNING, " got %u\n", res.nonce); - LOG (GNUNET_ERROR_TYPE_WARNING, " towards %s\n", GNUNET_i2s (&res.target)); - return; - } - - send_pong (t, res.nonce); -} - - -/** - * Peer has answer to our challenge. - * If answer is successful, consider the key exchange finished and clean - * up all related state. - * - * @param t Tunnel this message came on. - * @param msg Key eXchange Pong message. - */ -static void -handle_pong (struct CadetTunnel3 *t, - const struct GNUNET_CADET_KX_Pong *msg) -{ - uint32_t challenge; - - LOG (GNUNET_ERROR_TYPE_INFO, "<=== PONG for %s\n", GMT_2s (t)); - if (GNUNET_SCHEDULER_NO_TASK == t->rekey_task) - { - GNUNET_STATISTICS_update (stats, "# duplicate PONG messages", 1, GNUNET_NO); - return; - } - t_decrypt (t, &challenge, &msg->nonce, sizeof (uint32_t), msg->iv); - - if (challenge != t->kx_ctx->challenge) - { - LOG (GNUNET_ERROR_TYPE_WARNING, "Wrong PONG challenge\n"); - LOG (GNUNET_ERROR_TYPE_DEBUG, "PONG: %u (e: %u). Expected: %u.\n", - challenge, msg->nonce, t->kx_ctx->challenge); - GNUNET_break_op (0); - return; - } - GNUNET_SCHEDULER_cancel (t->rekey_task); - t->rekey_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_free (t->kx_ctx); - t->kx_ctx = NULL; - GMT_change_estate (t, CADET_TUNNEL3_KEY_OK); -} - - -/** - * Demultiplex by message type and call appropriate handler for a message - * towards a channel of a local tunnel. - * - * @param t Tunnel this message came on. - * @param msgh Message header. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -static void -handle_decrypted (struct CadetTunnel3 *t, - const struct GNUNET_MessageHeader *msgh, - int fwd) -{ - uint16_t type; - - type = ntohs (msgh->type); - LOG (GNUNET_ERROR_TYPE_INFO, "<=== %s on %s\n", GM_m2s (type), GMT_2s (t)); - - switch (type) - { - case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE: - /* Do nothing, connection aleady got updated. */ - GNUNET_STATISTICS_update (stats, "# keepalives received", 1, GNUNET_NO); - break; - - case GNUNET_MESSAGE_TYPE_CADET_DATA: - /* Don't send hop ACK, wait for client to ACK */ - handle_data (t, (struct GNUNET_CADET_Data *) msgh, fwd); - break; - - case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK: - handle_data_ack (t, (struct GNUNET_CADET_DataACK *) msgh, fwd); - break; - - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE: - handle_ch_create (t, - (struct GNUNET_CADET_ChannelCreate *) msgh); - break; - - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK: - handle_ch_nack (t, - (struct GNUNET_CADET_ChannelManage *) msgh); - break; - - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK: - handle_ch_ack (t, - (struct GNUNET_CADET_ChannelManage *) msgh, - fwd); - break; - - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: - handle_ch_destroy (t, - (struct GNUNET_CADET_ChannelManage *) msgh, - fwd); - break; - - default: - GNUNET_break_op (0); - LOG (GNUNET_ERROR_TYPE_WARNING, - "end-to-end message not known (%u)\n", - ntohs (msgh->type)); - GMT_debug (t); - } -} - -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ - -/** - * Decrypt and demultiplex by message type. Call appropriate handler - * for every message. - * - * @param t Tunnel this message came on. - * @param msg Encrypted message. - */ -void -GMT_handle_encrypted (struct CadetTunnel3 *t, - const struct GNUNET_CADET_Encrypted *msg) -{ - size_t size = ntohs (msg->header.size); - size_t payload_size = size - sizeof (struct GNUNET_CADET_Encrypted); - size_t decrypted_size; - char cbuf [payload_size]; - struct GNUNET_MessageHeader *msgh; - unsigned int off; - struct GNUNET_CADET_Hash hmac; - - decrypted_size = t_decrypt (t, cbuf, &msg[1], payload_size, msg->iv); - t_hmac (t, &msg[1], payload_size, msg->iv, GNUNET_NO, &hmac); - if (0 != memcmp (&hmac, &msg->hmac, sizeof (hmac))) - { - /* checksum failed */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed checksum validation for a message on tunnel `%s'\n", - GMT_2s (t)); - GNUNET_STATISTICS_update (stats, "# wrong HMAC", 1, GNUNET_NO); - return; - } - off = 0; - while (off < decrypted_size) - { - msgh = (struct GNUNET_MessageHeader *) &cbuf[off]; - handle_decrypted (t, msgh, GNUNET_SYSERR); - off += ntohs (msgh->size); - } -} - - -/** - * Demultiplex an encapsulated KX message by message type. - * - * @param t Tunnel on which the message came. - * @param message Payload of KX message. - */ -void -GMT_handle_kx (struct CadetTunnel3 *t, - const struct GNUNET_MessageHeader *message) -{ - uint16_t type; - - type = ntohs (message->type); - LOG (GNUNET_ERROR_TYPE_DEBUG, "kx message received\n", type); - switch (type) - { - case GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL: - handle_ephemeral (t, (struct GNUNET_CADET_KX_Ephemeral *) message); - break; - - case GNUNET_MESSAGE_TYPE_CADET_KX_PING: - handle_ping (t, (struct GNUNET_CADET_KX_Ping *) message); - break; - - case GNUNET_MESSAGE_TYPE_CADET_KX_PONG: - handle_pong (t, (struct GNUNET_CADET_KX_Pong *) message); - break; - - default: - GNUNET_break_op (0); - LOG (GNUNET_ERROR_TYPE_DEBUG, "kx message not known (%u)\n", type); - } -} - - -/** - * Initialize the tunnel subsystem. - * - * @param c Configuration handle. - * @param key ECC private key, to derive all other keys and do crypto. - */ -void -GMT_init (const struct GNUNET_CONFIGURATION_Handle *c, - const struct GNUNET_CRYPTO_EddsaPrivateKey *key) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (c, "CADET", "DEFAULT_TTL", - &default_ttl)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, - "CADET", "DEFAULT_TTL", "USING DEFAULT"); - default_ttl = 64; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (c, "CADET", "REKEY_PERIOD", - &rekey_period)) - { - rekey_period = GNUNET_TIME_UNIT_DAYS; - } - - my_private_key = key; - kx_msg.header.size = htons (sizeof (kx_msg)); - kx_msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL); - kx_msg.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CADET_KX); - kx_msg.purpose.size = htonl (ephemeral_purpose_size ()); - kx_msg.origin_identity = my_full_id; - rekey_task = GNUNET_SCHEDULER_add_now (&rekey, NULL); - - tunnels = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES); -} - - -/** - * Shut down the tunnel subsystem. - */ -void -GMT_shutdown (void) -{ - if (GNUNET_SCHEDULER_NO_TASK != rekey_task) - { - GNUNET_SCHEDULER_cancel (rekey_task); - rekey_task = GNUNET_SCHEDULER_NO_TASK; - } - GNUNET_CONTAINER_multipeermap_iterate (tunnels, &destroy_iterator, NULL); - GNUNET_CONTAINER_multipeermap_destroy (tunnels); -} - - -/** - * Create a tunnel. - * - * @param destination Peer this tunnel is towards. - */ -struct CadetTunnel3 * -GMT_new (struct CadetPeer *destination) -{ - struct CadetTunnel3 *t; - - t = GNUNET_new (struct CadetTunnel3); - t->next_chid = 0; - t->peer = destination; - - if (GNUNET_OK != - GNUNET_CONTAINER_multipeermap_put (tunnels, GMP_get_id (destination), t, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) - { - GNUNET_break (0); - GNUNET_free (t); - return NULL; - } - return t; -} - - -/** - * Change the tunnel's connection state. - * - * @param t Tunnel whose connection state to change. - * @param cstate New connection state. - */ -void -GMT_change_cstate (struct CadetTunnel3* t, enum CadetTunnel3CState cstate) -{ - if (NULL == t) - return; - LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s cstate %s => %s\n", - GMP_2s (t->peer), cstate2s (t->cstate), cstate2s (cstate)); - if (myid != GMP_get_short_id (t->peer) && - CADET_TUNNEL3_READY != t->cstate && - CADET_TUNNEL3_READY == cstate) - { - t->cstate = cstate; - if (CADET_TUNNEL3_KEY_OK == t->estate) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered send queued data\n"); - send_queued_data (t); - } - else if (CADET_TUNNEL3_KEY_UNINITIALIZED == t->estate) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered rekey\n"); - rekey_tunnel (t, NULL); - } - } - t->cstate = cstate; - - if (CADET_TUNNEL3_READY == cstate - && CONNECTIONS_PER_TUNNEL <= GMT_count_connections (t)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered stop dht\n"); - GMP_stop_search (t->peer); - } -} - -/** - * Change the tunnel encryption state. - * - * @param t Tunnel whose encryption state to change. - * @param state New encryption state. - */ -void -GMT_change_estate (struct CadetTunnel3* t, enum CadetTunnel3EState state) -{ - if (NULL == t) - return; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Tunnel %s estate was %s\n", - GMP_2s (t->peer), estate2s (t->estate)); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Tunnel %s estate is now %s\n", - GMP_2s (t->peer), estate2s (state)); - if (myid != GMP_get_short_id (t->peer) && - CADET_TUNNEL3_KEY_OK != t->estate && CADET_TUNNEL3_KEY_OK == state) - { - t->estate = state; - send_queued_data (t); - return; - } - t->estate = state; -} - - -/** - * @brief Check if tunnel has too many connections, and remove one if necessary. - * - * Currently this means the newest connection, unless it is a direct one. - * Implemented as a task to avoid freeing a connection that is in the middle - * of being created/processed. - * - * @param cls Closure (Tunnel to check). - * @param tc Task context. - */ -static void -trim_connections (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct CadetTunnel3 *t = cls; - - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; - - if (GMT_count_connections (t) > 2 * CONNECTIONS_PER_TUNNEL) - { - struct CadetTConnection *iter; - struct CadetTConnection *c; - - for (c = iter = t->connection_head; NULL != iter; iter = iter->next) - { - if ((NULL == c || iter->created.abs_value_us > c->created.abs_value_us) - && GNUNET_NO == GMC_is_direct (iter->c)) - { - c = iter; - } - } - if (NULL != c) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Too many connections on tunnel %s\n", - GMT_2s (t)); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying connection %s\n", - GMC_2s (c->c)); - GMC_destroy (c->c); - } - else - { - GNUNET_break (0); - } - } -} - - -/** - * Add a connection to a tunnel. - * - * @param t Tunnel. - * @param c Connection. - */ -void -GMT_add_connection (struct CadetTunnel3 *t, struct CadetConnection *c) -{ - struct CadetTConnection *aux; - - GNUNET_assert (NULL != c); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "add connection %s\n", GMC_2s (c)); - LOG (GNUNET_ERROR_TYPE_DEBUG, " to tunnel %s\n", GMT_2s (t)); - for (aux = t->connection_head; aux != NULL; aux = aux->next) - if (aux->c == c) - return; - - aux = GNUNET_new (struct CadetTConnection); - aux->c = c; - aux->created = GNUNET_TIME_absolute_get (); - - GNUNET_CONTAINER_DLL_insert (t->connection_head, t->connection_tail, aux); - - GNUNET_SCHEDULER_add_now (&trim_connections, t); -} - - -/** - * Mark a path as no longer valid for this tunnel: has been tried and failed. - * - * @param t Tunnel to update. - * @param path Invalid path to remove. Is destroyed after removal. - */ -void -GMT_remove_path (struct CadetTunnel3 *t, struct CadetPeerPath *path) -{ - GMP_remove_path (t->peer, path); -} - - -/** - * Remove a connection from a tunnel. - * - * @param t Tunnel. - * @param c Connection. - */ -void -GMT_remove_connection (struct CadetTunnel3 *t, - struct CadetConnection *c) -{ - struct CadetTConnection *aux; - struct CadetTConnection *next; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing connection %s from tunnel %s\n", - GMC_2s (c), GMT_2s (t)); - for (aux = t->connection_head; aux != NULL; aux = next) - { - next = aux->next; - if (aux->c == c) - { - GNUNET_CONTAINER_DLL_remove (t->connection_head, t->connection_tail, aux); - GNUNET_free (aux); - } - } - - /* Start new connections if needed */ - if (CONNECTIONS_PER_TUNNEL < GMT_count_connections (t) - && GNUNET_SCHEDULER_NO_TASK == t->destroy_task - && CADET_TUNNEL3_SHUTDOWN != t->cstate - && GNUNET_NO == shutting_down) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " no more connections, getting new ones\n"); - t->cstate = CADET_TUNNEL3_SEARCHING; - GMP_connect (t->peer); - return; - } - - /* If not marked as ready, no change is needed */ - if (CADET_TUNNEL3_READY != t->cstate) - return; - - /* Check if any connection is ready to maintaing cstate */ - for (aux = t->connection_head; aux != NULL; aux = aux->next) - if (CADET_CONNECTION_READY == GMC_get_state (aux->c)) - return; - - t->cstate = CADET_TUNNEL3_WAITING; -} - - -/** - * Add a channel to a tunnel. - * - * @param t Tunnel. - * @param ch Channel. - */ -void -GMT_add_channel (struct CadetTunnel3 *t, struct CadetChannel *ch) -{ - struct CadetTChannel *aux; - - GNUNET_assert (NULL != ch); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding channel %p to tunnel %p\n", ch, t); - - for (aux = t->channel_head; aux != NULL; aux = aux->next) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " already there %p\n", aux->ch); - if (aux->ch == ch) - return; - } - - aux = GNUNET_new (struct CadetTChannel); - aux->ch = ch; - LOG (GNUNET_ERROR_TYPE_DEBUG, " adding %p to %p\n", aux, t->channel_head); - GNUNET_CONTAINER_DLL_insert_tail (t->channel_head, t->channel_tail, aux); - - if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task) - { - GNUNET_SCHEDULER_cancel (t->destroy_task); - t->destroy_task = GNUNET_SCHEDULER_NO_TASK; - LOG (GNUNET_ERROR_TYPE_DEBUG, " undo destroy!\n"); - } -} - - -/** - * Remove a channel from a tunnel. - * - * @param t Tunnel. - * @param ch Channel. - */ -void -GMT_remove_channel (struct CadetTunnel3 *t, struct CadetChannel *ch) -{ - struct CadetTChannel *aux; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing channel %p from tunnel %p\n", ch, t); - for (aux = t->channel_head; aux != NULL; aux = aux->next) - { - if (aux->ch == ch) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " found! %s\n", GMCH_2s (ch)); - GNUNET_CONTAINER_DLL_remove (t->channel_head, t->channel_tail, aux); - GNUNET_free (aux); - return; - } - } -} - - -/** - * Search for a channel by global ID. - * - * @param t Tunnel containing the channel. - * @param chid Public channel number. - * - * @return channel handler, NULL if doesn't exist - */ -struct CadetChannel * -GMT_get_channel (struct CadetTunnel3 *t, CADET_ChannelNumber chid) -{ - struct CadetTChannel *iter; - - if (NULL == t) - return NULL; - - for (iter = t->channel_head; NULL != iter; iter = iter->next) - { - if (GMCH_get_id (iter->ch) == chid) - break; - } - - return NULL == iter ? NULL : iter->ch; -} - - -/** - * @brief Destroy a tunnel and free all resources. - * - * Should only be called a while after the tunnel has been marked as destroyed, - * in case there is a new channel added to the same peer shortly after marking - * the tunnel. This way we avoid a new public key handshake. - * - * @param cls Closure (tunnel to destroy). - * @param tc Task context. - */ -static void -delayed_destroy (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct CadetTunnel3 *t = cls; - struct CadetTConnection *iter; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "delayed destroying tunnel %p\n", t); - if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - "Not destroying tunnel, due to shutdown. " - "Tunnel at %p should have been freed by GMT_shutdown\n", t); - return; - } - t->destroy_task = GNUNET_SCHEDULER_NO_TASK; - t->cstate = CADET_TUNNEL3_SHUTDOWN; - - for (iter = t->connection_head; NULL != iter; iter = iter->next) - { - GMC_send_destroy (iter->c); - } - GMT_destroy (t); -} - - -/** - * Tunnel is empty: destroy it. - * - * Notifies all connections about the destruction. - * - * @param t Tunnel to destroy. - */ -void -GMT_destroy_empty (struct CadetTunnel3 *t) -{ - if (GNUNET_YES == shutting_down) - return; /* Will be destroyed immediately anyway */ - - if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Tunnel %s is already scheduled for destruction\n", - GMT_2s (t)); - GNUNET_break (0); - /* should never happen, tunnel can only become empty once, and the - * task identifier should be NO_TASK (cleaned when the tunnel was created - * or became un-empty) - */ - return; - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s empty: destroying scheduled\n", - GMT_2s (t)); - - t->destroy_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, - &delayed_destroy, t); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduled destroy of %p as %llX\n", - t, t->destroy_task); -} - - -/** - * Destroy tunnel if empty (no more channels). - * - * @param t Tunnel to destroy if empty. - */ -void -GMT_destroy_if_empty (struct CadetTunnel3 *t) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s destroy if empty\n", GMT_2s (t)); - if (1 < GMT_count_channels (t)) - return; - - GMT_destroy_empty (t); -} - - -/** - * Destroy the tunnel. - * - * This function does not generate any warning traffic to clients or peers. - * - * Tasks: - * Cancel messages belonging to this tunnel queued to neighbors. - * Free any allocated resources linked to the tunnel. - * - * @param t The tunnel to destroy. - */ -void -GMT_destroy (struct CadetTunnel3 *t) -{ - struct CadetTConnection *iter_c; - struct CadetTConnection *next_c; - struct CadetTChannel *iter_ch; - struct CadetTChannel *next_ch; - - if (NULL == t) - return; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying tunnel %s\n", GMP_2s (t->peer)); - - GNUNET_break (GNUNET_YES == - GNUNET_CONTAINER_multipeermap_remove (tunnels, - GMP_get_id (t->peer), t)); - - for (iter_c = t->connection_head; NULL != iter_c; iter_c = next_c) - { - next_c = iter_c->next; - GMC_destroy (iter_c->c); - } - for (iter_ch = t->channel_head; NULL != iter_ch; iter_ch = next_ch) - { - next_ch = iter_ch->next; - GMCH_destroy (iter_ch->ch); - /* Should only happen on shutdown, but it's ok. */ - } - - if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "cancelling %llX\n", t->destroy_task); - GNUNET_SCHEDULER_cancel (t->destroy_task); - t->destroy_task = GNUNET_SCHEDULER_NO_TASK; - } - - GNUNET_STATISTICS_update (stats, "# tunnels", -1, GNUNET_NO); - GMP_set_tunnel (t->peer, NULL); - - if (GNUNET_SCHEDULER_NO_TASK != t->rekey_task) - { - GNUNET_SCHEDULER_cancel (t->rekey_task); - t->rekey_task = GNUNET_SCHEDULER_NO_TASK; - if (NULL != t->kx_ctx) - GNUNET_free (t->kx_ctx); - else - GNUNET_break (0); - } - - GNUNET_free (t); -} - - -/** - * @brief Use the given path for the tunnel. - * Update the next and prev hops (and RCs). - * (Re)start the path refresh in case the tunnel is locally owned. - * - * @param t Tunnel to update. - * @param p Path to use. - * - * @return Connection created. - */ -struct CadetConnection * -GMT_use_path (struct CadetTunnel3 *t, struct CadetPeerPath *p) -{ - struct CadetConnection *c; - struct GNUNET_CADET_Hash cid; - unsigned int own_pos; - - if (NULL == t || NULL == p) - { - GNUNET_break (0); - return NULL; - } - - if (CADET_TUNNEL3_SHUTDOWN == t->cstate) - { - GNUNET_break (0); - return NULL; - } - - for (own_pos = 0; own_pos < p->length; own_pos++) - { - if (p->peers[own_pos] == myid) - break; - } - if (own_pos >= p->length) - { - GNUNET_break_op (0); - return NULL; - } - - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, &cid, sizeof (cid)); - c = GMC_new (&cid, t, p, own_pos); - if (NULL == c) - { - /* Path was flawed */ - return NULL; - } - GMT_add_connection (t, c); - return c; -} - - -/** - * Count established (ready) connections of a tunnel. - * - * @param t Tunnel on which to count. - * - * @return Number of connections. - */ -unsigned int -GMT_count_connections (struct CadetTunnel3 *t) -{ - struct CadetTConnection *iter; - unsigned int count; - - if (NULL == t) - return 0; - - for (count = 0, iter = t->connection_head; NULL != iter; iter = iter->next) - if (CADET_CONNECTION_DESTROYED != GMC_get_state (iter->c)) - count++; - - return count; -} - -/** - * Count channels of a tunnel. - * - * @param t Tunnel on which to count. - * - * @return Number of channels. - */ -unsigned int -GMT_count_channels (struct CadetTunnel3 *t) -{ - struct CadetTChannel *iter; - unsigned int count; - - for (count = 0, iter = t->channel_head; - NULL != iter; - iter = iter->next, count++) /* skip */; - - return count; -} - - -/** - * Get the connectivity state of a tunnel. - * - * @param t Tunnel. - * - * @return Tunnel's connectivity state. - */ -enum CadetTunnel3CState -GMT_get_cstate (struct CadetTunnel3 *t) -{ - if (NULL == t) - { - GNUNET_assert (0); - return (enum CadetTunnel3CState) -1; - } - return t->cstate; -} - - -/** - * Get the encryption state of a tunnel. - * - * @param t Tunnel. - * - * @return Tunnel's encryption state. - */ -enum CadetTunnel3EState -GMT_get_estate (struct CadetTunnel3 *t) -{ - if (NULL == t) - { - GNUNET_assert (0); - return (enum CadetTunnel3EState) -1; - } - return t->estate; -} - -/** - * Get the maximum buffer space for a tunnel towards a local client. - * - * @param t Tunnel. - * - * @return Biggest buffer space offered by any channel in the tunnel. - */ -unsigned int -GMT_get_channels_buffer (struct CadetTunnel3 *t) -{ - struct CadetTChannel *iter; - unsigned int buffer; - unsigned int ch_buf; - - if (NULL == t->channel_head) - { - /* Probably getting buffer for a channel create/handshake. */ - return 64; - } - - buffer = 0; - for (iter = t->channel_head; NULL != iter; iter = iter->next) - { - ch_buf = get_channel_buffer (iter); - if (ch_buf > buffer) - buffer = ch_buf; - } - return buffer; -} - - -/** - * Get the total buffer space for a tunnel for P2P traffic. - * - * @param t Tunnel. - * - * @return Buffer space offered by all connections in the tunnel. - */ -unsigned int -GMT_get_connections_buffer (struct CadetTunnel3 *t) -{ - struct CadetTConnection *iter; - unsigned int buffer; - - buffer = 0; - for (iter = t->connection_head; NULL != iter; iter = iter->next) - { - if (GMC_get_state (iter->c) != CADET_CONNECTION_READY) - { - continue; - } - buffer += get_connection_buffer (iter); - } - - return buffer; -} - - -/** - * Get the tunnel's destination. - * - * @param t Tunnel. - * - * @return ID of the destination peer. - */ -const struct GNUNET_PeerIdentity * -GMT_get_destination (struct CadetTunnel3 *t) -{ - return GMP_get_id (t->peer); -} - - -/** - * Get the tunnel's next free global channel ID. - * - * @param t Tunnel. - * - * @return GID of a channel free to use. - */ -CADET_ChannelNumber -GMT_get_next_chid (struct CadetTunnel3 *t) -{ - CADET_ChannelNumber chid; - CADET_ChannelNumber mask; - int result; - - /* Set bit 30 depending on the ID relationship. Bit 31 is always 0 for GID. - * If our ID is bigger or loopback tunnel, start at 0, bit 30 = 0 - * If peer's ID is bigger, start at 0x4... bit 30 = 1 - */ - result = GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, GMP_get_id (t->peer)); - if (0 > result) - mask = 0x40000000; - else - mask = 0x0; - t->next_chid |= mask; - - while (NULL != GMT_get_channel (t, t->next_chid)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %u exists...\n", t->next_chid); - t->next_chid = (t->next_chid + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI; - t->next_chid |= mask; - } - chid = t->next_chid; - t->next_chid = (t->next_chid + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI; - t->next_chid |= mask; - - return chid; -} - - -/** - * Send ACK on one or more channels due to buffer in connections. - * - * @param t Channel which has some free buffer space. - */ -void -GMT_unchoke_channels (struct CadetTunnel3 *t) -{ - struct CadetTChannel *iter; - unsigned int buffer; - unsigned int channels = GMT_count_channels (t); - unsigned int choked_n; - struct CadetChannel *choked[channels]; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT_unchoke_channels on %s\n", GMT_2s (t)); - LOG (GNUNET_ERROR_TYPE_DEBUG, " head: %p\n", t->channel_head); - if (NULL != t->channel_head) - LOG (GNUNET_ERROR_TYPE_DEBUG, " head ch: %p\n", t->channel_head->ch); - - /* Get buffer space */ - buffer = GMT_get_connections_buffer (t); - if (0 == buffer) - { - return; - } - - /* Count and remember choked channels */ - choked_n = 0; - for (iter = t->channel_head; NULL != iter; iter = iter->next) - { - if (GNUNET_NO == get_channel_allowed (iter)) - { - choked[choked_n++] = iter->ch; - } - } - - /* Unchoke random channels */ - while (0 < buffer && 0 < choked_n) - { - unsigned int r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, - choked_n); - GMCH_allow_client (choked[r], GMCH_is_origin (choked[r], GNUNET_YES)); - choked_n--; - buffer--; - choked[r] = choked[choked_n]; - } -} - - -/** - * Send ACK on one or more connections due to buffer space to the client. - * - * Iterates all connections of the tunnel and sends ACKs appropriately. - * - * @param t Tunnel. - */ -void -GMT_send_connection_acks (struct CadetTunnel3 *t) -{ - struct CadetTConnection *iter; - uint32_t allowed; - uint32_t to_allow; - uint32_t allow_per_connection; - unsigned int cs; - unsigned int buffer; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel send connection ACKs on %s\n", - GMT_2s (t)); - - if (NULL == t) - { - GNUNET_break (0); - return; - } - - buffer = GMT_get_channels_buffer (t); - LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer %u\n", buffer); - - /* Count connections, how many messages are already allowed */ - cs = GMT_count_connections (t); - for (allowed = 0, iter = t->connection_head; NULL != iter; iter = iter->next) - { - allowed += get_connection_allowed (iter); - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " allowed %u\n", allowed); - - /* Make sure there is no overflow */ - if (allowed > buffer) - { - return; - } - - /* Authorize connections to send more data */ - to_allow = buffer; /* - allowed; */ - - for (iter = t->connection_head; - NULL != iter && to_allow > 0; - iter = iter->next) - { - allow_per_connection = to_allow/cs; - to_allow -= allow_per_connection; - cs--; - if (get_connection_allowed (iter) > 64 / 3) - { - continue; - } - GMC_allow (iter->c, allow_per_connection, - GMC_is_origin (iter->c, GNUNET_NO)); - } - - GNUNET_break (to_allow == 0); -} - - -/** - * Cancel a previously sent message while it's in the queue. - * - * ONLY can be called before the continuation given to the send function - * is called. Once the continuation is called, the message is no longer in the - * queue. - * - * @param q Handle to the queue. - */ -void -GMT_cancel (struct CadetTunnel3Queue *q) -{ - if (NULL != q->cq) - { - GMC_cancel (q->cq); - /* tun_message_sent() will be called and free q */ - } - else if (NULL != q->tqd) - { - unqueue_data (q->tqd); - q->tqd = NULL; - if (NULL != q->cont) - q->cont (q->cont_cls, NULL, q, 0, 0); - GNUNET_free (q); - } - else - { - GNUNET_break (0); - } -} - - -/** - * Sends an already built message on a tunnel, encrypting it and - * choosing the best connection if not provided. - * - * @param message Message to send. Function modifies it. - * @param t Tunnel on which this message is transmitted. - * @param c Connection to use (autoselect if NULL). - * @param force Force the tunnel to take the message (buffer overfill). - * @param cont Continuation to call once message is really sent. - * @param cont_cls Closure for @c cont. - * - * @return Handle to cancel message. NULL if @c cont is NULL. - */ -struct CadetTunnel3Queue * -GMT_send_prebuilt_message (const struct GNUNET_MessageHeader *message, - struct CadetTunnel3 *t, struct CadetConnection *c, - int force, GMT_sent cont, void *cont_cls) -{ - return send_prebuilt_message (message, t, c, force, cont, cont_cls, NULL); -} - - -/** - * Is the tunnel directed towards the local peer? - * - * @param t Tunnel. - * - * @return #GNUNET_YES if it is loopback. - */ -int -GMT_is_loopback (const struct CadetTunnel3 *t) -{ - return (myid == GMP_get_short_id (t->peer)); -} - - -/** - * Is the tunnel this path already? - * - * @param t Tunnel. - * @param p Path. - * - * @return #GNUNET_YES a connection uses this path. - */ -int -GMT_is_path_used (const struct CadetTunnel3 *t, const struct CadetPeerPath *p) -{ - struct CadetTConnection *iter; - - for (iter = t->connection_head; NULL != iter; iter = iter->next) - if (GMC_get_path (iter->c) == p) - return GNUNET_YES; - - return GNUNET_NO; -} - - -/** - * Get a cost of a path for a tunnel considering existing connections. - * - * @param t Tunnel. - * @param path Candidate path. - * - * @return Cost of the path (path length + number of overlapping nodes) - */ -unsigned int -GMT_get_path_cost (const struct CadetTunnel3 *t, - const struct CadetPeerPath *path) -{ - struct CadetTConnection *iter; - const struct CadetPeerPath *aux; - unsigned int overlap; - unsigned int i; - unsigned int j; - - if (NULL == path) - return 0; - - overlap = 0; - GNUNET_assert (NULL != t); - - for (i = 0; i < path->length; i++) - { - for (iter = t->connection_head; NULL != iter; iter = iter->next) - { - aux = GMC_get_path (iter->c); - if (NULL == aux) - continue; - - for (j = 0; j < aux->length; j++) - { - if (path->peers[i] == aux->peers[j]) - { - overlap++; - break; - } - } - } - } - return path->length + overlap; -} - - -/** - * Get the static string for the peer this tunnel is directed. - * - * @param t Tunnel. - * - * @return Static string the destination peer's ID. - */ -const char * -GMT_2s (const struct CadetTunnel3 *t) -{ - if (NULL == t) - return "(NULL)"; - - return GMP_2s (t->peer); -} - - -/******************************************************************************/ -/***************************** INFO/DEBUG *******************************/ -/******************************************************************************/ - - -/** - * Log all possible info about the tunnel state to stderr. - * - * @param t Tunnel to debug. - */ -void -GMT_debug (const struct CadetTunnel3 *t) -{ - struct CadetTChannel *iterch; - struct CadetTConnection *iterc; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT DEBUG TUNNEL TOWARDS %s\n", GMT_2s (t)); - LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT cstate %s, estate %s\n", - cstate2s (t->cstate), estate2s (t->estate)); - LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT kx_ctx %p, rekey_task %u\n", - t->kx_ctx, t->rekey_task); - LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT tq_head %p, tq_tail %p\n", - t->tq_head, t->tq_tail); - LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT destroy %u\n", t->destroy_task); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT channels:\n"); - for (iterch = t->channel_head; NULL != iterch; iterch = iterch->next) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT - %s\n", GMCH_2s (iterch->ch)); - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT connections:\n"); - for (iterc = t->connection_head; NULL != iterc; iterc = iterc->next) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT - %s [%u] buf: %u/%u (qn %u/%u)\n", - GMC_2s (iterc->c), GMC_get_state (iterc->c), - GMC_get_buffer (iterc->c, GNUNET_YES), - GMC_get_buffer (iterc->c, GNUNET_NO), - GMC_get_qn (iterc->c, GNUNET_YES), - GMC_get_qn (iterc->c, GNUNET_NO)); - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT DEBUG TUNNEL END\n"); -} - - -/** - * Iterate all tunnels. - * - * @param iter Iterator. - * @param cls Closure for @c iter. - */ -void -GMT_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls) -{ - GNUNET_CONTAINER_multipeermap_iterate (tunnels, iter, cls); -} - - -/** - * Count all tunnels. - * - * @return Number of tunnels to remote peers kept by this peer. - */ -unsigned int -GMT_count_all (void) -{ - return GNUNET_CONTAINER_multipeermap_size (tunnels); -} - - -/** - * Iterate all connections of a tunnel. - * - * @param t Tunnel whose connections to iterate. - * @param iter Iterator. - * @param cls Closure for @c iter. - */ -void -GMT_iterate_connections (struct CadetTunnel3 *t, GMT_conn_iter iter, void *cls) -{ - struct CadetTConnection *ct; - - for (ct = t->connection_head; NULL != ct; ct = ct->next) - iter (cls, ct->c); -} - - -/** - * Iterate all channels of a tunnel. - * - * @param t Tunnel whose channels to iterate. - * @param iter Iterator. - * @param cls Closure for @c iter. - */ -void -GMT_iterate_channels (struct CadetTunnel3 *t, GMT_chan_iter iter, void *cls) -{ - struct CadetTChannel *cht; - - for (cht = t->channel_head; NULL != cht; cht = cht->next) - iter (cls, cht->ch); -} diff --git a/src/mesh/gnunet-service-cadet_tunnel.h b/src/mesh/gnunet-service-cadet_tunnel.h deleted file mode 100644 index 16616de59..000000000 --- a/src/mesh/gnunet-service-cadet_tunnel.h +++ /dev/null @@ -1,531 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2013 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 cadet/gnunet-service-cadet_tunnel.h - * @brief cadet service; dealing with tunnels and crypto - * @author Bartlomiej Polot - * - * All functions in this file should use the prefix GMT (Gnunet Cadet Tunnel) - */ - -#ifndef GNUNET_SERVICE_CADET_TUNNEL_H -#define GNUNET_SERVICE_CADET_TUNNEL_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "platform.h" -#include "gnunet_util_lib.h" - -/** - * All the connectivity states a tunnel can be in. - */ -enum CadetTunnel3CState -{ - /** - * Uninitialized status, should never appear in operation. - */ - CADET_TUNNEL3_NEW, - - /** - * Path to the peer not known yet. - */ - CADET_TUNNEL3_SEARCHING, - - /** - * Request sent, not yet answered. - */ - CADET_TUNNEL3_WAITING, - - /** - * Peer connected and ready to accept data. - */ - CADET_TUNNEL3_READY, - - /** - * Tunnel being shut down, don't try to keep it alive. - */ - CADET_TUNNEL3_SHUTDOWN -}; - - -/** - * All the encryption states a tunnel can be in. - */ -enum CadetTunnel3EState -{ - /** - * Uninitialized status, should never appear in operation. - */ - CADET_TUNNEL3_KEY_UNINITIALIZED, - - /** - * Ephemeral key sent, waiting for peer's key. - */ - CADET_TUNNEL3_KEY_SENT, - - /** - * New ephemeral key and ping sent, waiting for pong. - * This means that we DO have the peer's ephemeral key, otherwise the - * state would be KEY_SENT. - */ - CADET_TUNNEL3_KEY_PING, - - /** - * Handshake completed: session key available. - */ - CADET_TUNNEL3_KEY_OK, -}; - -/** - * Struct containing all information regarding a given peer - */ -struct CadetTunnel3; - - -#include "gnunet-service-cadet_channel.h" -#include "gnunet-service-cadet_connection.h" -#include "gnunet-service-cadet_peer.h" - -/** - * Handle for messages queued but not yet sent. - */ -struct CadetTunnel3Queue; - -/** - * Callback called when a queued message is sent. - * - * @param cls Closure. - * @param t Tunnel this message was on. - * @param type Type of message sent. - * @param size Size of the message. - */ -typedef void (*GMT_sent) (void *cls, - struct CadetTunnel3 *t, - struct CadetTunnel3Queue *q, - uint16_t type, size_t size); - -typedef void (*GMT_conn_iter) (void *cls, struct CadetConnection *c); -typedef void (*GMT_chan_iter) (void *cls, struct CadetChannel *ch); - - -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ - -/** - * Initialize tunnel subsystem. - * - * @param c Configuration handle. - * @param key ECC private key, to derive all other keys and do crypto. - */ -void -GMT_init (const struct GNUNET_CONFIGURATION_Handle *c, - const struct GNUNET_CRYPTO_EddsaPrivateKey *key); - -/** - * Shut down the tunnel subsystem. - */ -void -GMT_shutdown (void); - -/** - * Create a tunnel. - * - * @param destination Peer this tunnel is towards. - */ -struct CadetTunnel3 * -GMT_new (struct CadetPeer *destination); - -/** - * Tunnel is empty: destroy it. - * - * Notifies all connections about the destruction. - * - * @param t Tunnel to destroy. - */ -void -GMT_destroy_empty (struct CadetTunnel3 *t); - -/** - * Destroy tunnel if empty (no more channels). - * - * @param t Tunnel to destroy if empty. - */ -void -GMT_destroy_if_empty (struct CadetTunnel3 *t); - -/** - * Destroy the tunnel. - * - * This function does not generate any warning traffic to clients or peers. - * - * Tasks: - * Cancel messages belonging to this tunnel queued to neighbors. - * Free any allocated resources linked to the tunnel. - * - * @param t The tunnel to destroy. - */ -void -GMT_destroy (struct CadetTunnel3 *t); - - -/** - * Change the tunnel's connection state. - * - * @param t Tunnel whose connection state to change. - * @param cstate New connection state. - */ -void -GMT_change_cstate (struct CadetTunnel3* t, enum CadetTunnel3CState cstate); - - -/** - * Change the tunnel encryption state. - * - * @param t Tunnel whose encryption state to change. - * @param state New encryption state. - */ -void -GMT_change_estate (struct CadetTunnel3* t, enum CadetTunnel3EState state); - -/** - * Add a connection to a tunnel. - * - * @param t Tunnel. - * @param c Connection. - */ -void -GMT_add_connection (struct CadetTunnel3 *t, struct CadetConnection *c); - -/** - * Mark a path as no longer valid for this tunnel: has been tried and failed. - * - * @param t Tunnel to update. - * @param path Invalid path to remove. Is destroyed after removal. - */ -void -GMT_remove_path (struct CadetTunnel3 *t, struct CadetPeerPath *path); - -/** - * Remove a connection from a tunnel. - * - * @param t Tunnel. - * @param c Connection. - */ -void -GMT_remove_connection (struct CadetTunnel3 *t, struct CadetConnection *c); - -/** - * Add a channel to a tunnel. - * - * @param t Tunnel. - * @param ch Channel. - */ -void -GMT_add_channel (struct CadetTunnel3 *t, struct CadetChannel *ch); - -/** - * Remove a channel from a tunnel. - * - * @param t Tunnel. - * @param ch Channel. - */ -void -GMT_remove_channel (struct CadetTunnel3 *t, struct CadetChannel *ch); - -/** - * Search for a channel by global ID. - * - * @param t Tunnel containing the channel. - * @param chid Public channel number. - * - * @return channel handler, NULL if doesn't exist - */ -struct CadetChannel * -GMT_get_channel (struct CadetTunnel3 *t, CADET_ChannelNumber chid); - -/** - * Decrypt and demultiplex by message type. Call appropriate handler - * for a message - * towards a channel of a local tunnel. - * - * @param t Tunnel this message came on. - * @param msg Message header. - */ -void -GMT_handle_encrypted (struct CadetTunnel3 *t, - const struct GNUNET_CADET_Encrypted *msg); - -/** - * Demultiplex an encapsulated KX message by message type. - * - * @param t Tunnel on which the message came. - * @param message KX message itself. - */ -void -GMT_handle_kx (struct CadetTunnel3 *t, - const struct GNUNET_MessageHeader *message); - -/** - * @brief Use the given path for the tunnel. - * Update the next and prev hops (and RCs). - * (Re)start the path refresh in case the tunnel is locally owned. - * - * @param t Tunnel to update. - * @param p Path to use. - * - * @return Connection created. - */ -struct CadetConnection * -GMT_use_path (struct CadetTunnel3 *t, struct CadetPeerPath *p); - -/** - * Count established (ready) connections of a tunnel. - * - * @param t Tunnel on which to count. - * - * @return Number of connections. - */ -unsigned int -GMT_count_connections (struct CadetTunnel3 *t); - -/** - * Count channels of a tunnel. - * - * @param t Tunnel on which to count. - * - * @return Number of channels. - */ -unsigned int -GMT_count_channels (struct CadetTunnel3 *t); - -/** - * Get the connectivity state of a tunnel. - * - * @param t Tunnel. - * - * @return Tunnel's connectivity state. - */ -enum CadetTunnel3CState -GMT_get_cstate (struct CadetTunnel3 *t); - -/** - * Get the encryption state of a tunnel. - * - * @param t Tunnel. - * - * @return Tunnel's encryption state. - */ -enum CadetTunnel3EState -GMT_get_estate (struct CadetTunnel3 *t); - -/** - * Get the maximum buffer space for a tunnel towards a local client. - * - * @param t Tunnel. - * - * @return Biggest buffer space offered by any channel in the tunnel. - */ -unsigned int -GMT_get_channels_buffer (struct CadetTunnel3 *t); - -/** - * Get the total buffer space for a tunnel for P2P traffic. - * - * @param t Tunnel. - * - * @return Buffer space offered by all connections in the tunnel. - */ -unsigned int -GMT_get_connections_buffer (struct CadetTunnel3 *t); - -/** - * Get the tunnel's destination. - * - * @param t Tunnel. - * - * @return ID of the destination peer. - */ -const struct GNUNET_PeerIdentity * -GMT_get_destination (struct CadetTunnel3 *t); - -/** - * Get the tunnel's next free Channel ID. - * - * @param t Tunnel. - * - * @return ID of a channel free to use. - */ -CADET_ChannelNumber -GMT_get_next_chid (struct CadetTunnel3 *t); - -/** - * Send ACK on one or more channels due to buffer in connections. - * - * @param t Channel which has some free buffer space. - */ -void -GMT_unchoke_channels (struct CadetTunnel3 *t); - -/** - * Send ACK on one or more connections due to buffer space to the client. - * - * Iterates all connections of the tunnel and sends ACKs appropriately. - * - * @param t Tunnel which has some free buffer space. - */ -void -GMT_send_connection_acks (struct CadetTunnel3 *t); - -/** - * Cancel a previously sent message while it's in the queue. - * - * ONLY can be called before the continuation given to the send function - * is called. Once the continuation is called, the message is no longer in the - * queue. - * - * @param q Handle to the queue. - */ -void -GMT_cancel (struct CadetTunnel3Queue *q); - -/** - * Sends an already built message on a tunnel, encrypting it and - * choosing the best connection. - * - * @param message Message to send. Function modifies it. - * @param t Tunnel on which this message is transmitted. - * @param c Connection to use (autoselect if NULL). - * @param force Force the tunnel to take the message (buffer overfill). - * @param cont Continuation to call once message is really sent. - * @param cont_cls Closure for @c cont. - * - * @return Handle to cancel message. NULL if @c cont is NULL. - */ -struct CadetTunnel3Queue * -GMT_send_prebuilt_message (const struct GNUNET_MessageHeader *message, - struct CadetTunnel3 *t, struct CadetConnection *c, - int force, GMT_sent cont, void *cont_cls); - -/** - * Is the tunnel directed towards the local peer? - * - * @param t Tunnel. - * - * @return #GNUNET_YES if it is loopback. - */ -int -GMT_is_loopback (const struct CadetTunnel3 *t); - -/** - * Is the tunnel using this path already? - * - * @param t Tunnel. - * @param p Path. - * - * @return #GNUNET_YES a connection uses this path. - */ -int -GMT_is_path_used (const struct CadetTunnel3 *t, const struct CadetPeerPath *p); - -/** - * Get a cost of a path for a tunnel considering existing connections. - * - * @param t Tunnel. - * @param path Candidate path. - * - * @return Cost of the path (path length + number of overlapping nodes) - */ -unsigned int -GMT_get_path_cost (const struct CadetTunnel3 *t, - const struct CadetPeerPath *path); - -/** - * Get the static string for the peer this tunnel is directed. - * - * @param t Tunnel. - * - * @return Static string the destination peer's ID. - */ -const char * -GMT_2s (const struct CadetTunnel3 *t); - -/** - * Log all possible info about the tunnel state. - * - * @param t Tunnel to debug. - */ -void -GMT_debug (const struct CadetTunnel3 *t); - -/** - * Iterate all tunnels. - * - * @param iter Iterator. - * @param cls Closure for @c iter. - */ -void -GMT_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls); - -/** - * Count all tunnels. - * - * @return Number of tunnels to remote peers kept by this peer. - */ -unsigned int -GMT_count_all (void); - -/** - * Iterate all connections of a tunnel. - * - * @param t Tunnel whose connections to iterate. - * @param iter Iterator. - * @param cls Closure for @c iter. - */ -void -GMT_iterate_connections (struct CadetTunnel3 *t, GMT_conn_iter iter, void *cls); - -/** - * Iterate all channels of a tunnel. - * - * @param t Tunnel whose channels to iterate. - * @param iter Iterator. - * @param cls Closure for @c iter. - */ -void -GMT_iterate_channels (struct CadetTunnel3 *t, GMT_chan_iter iter, void *cls); - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_CADET_SERVICE_TUNNEL_H */ -#endif -/* end of gnunet-cadet-service_tunnel.h */ diff --git a/src/mesh/loopcheck.sh b/src/mesh/loopcheck.sh deleted file mode 100755 index 2ea737ecb..000000000 --- a/src/mesh/loopcheck.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -while true; do - date; - taskset 1 make check || break; - grep -B 10 Assert *log && break - ls core* &> /dev/null && break -done diff --git a/src/mesh/mesh.conf.in b/src/mesh/mesh.conf.in deleted file mode 100644 index c6bb09dd7..000000000 --- a/src/mesh/mesh.conf.in +++ /dev/null @@ -1,21 +0,0 @@ -[mesh] -AUTOSTART = @AUTOSTART@ -@JAVAPORT@PORT = 2096 -HOSTNAME = localhost -BINARY = gnunet-service-mesh -ACCEPT_FROM = 127.0.0.1; -ACCEPT_FROM6 = ::1; -UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-mesh.sock -UNIX_MATCH_UID = YES -UNIX_MATCH_GID = YES -REFRESH_CONNECTION_TIME = 5 min -ID_ANNOUNCE_TIME = 1 h -APP_ANNOUNCE_TIME = 1 h -CONNECT_TIMEOUT = 30 s -DEFAULT_TTL = 64 -DHT_REPLICATION_LEVEL = 3 -MAX_TUNNELS = 1000 -# MAX_TUNNELS deprecated -MAX_CONNECTIONS = 1000 -MAX_MSGS_QUEUE = 10000 -MAX_PEERS = 1000 diff --git a/src/mesh/profiler.conf b/src/mesh/profiler.conf deleted file mode 100644 index 8817802d1..000000000 --- a/src/mesh/profiler.conf +++ /dev/null @@ -1,19 +0,0 @@ -@INLINE@ test_mesh.conf - -[testbed] -OVERLAY_TOPOLOGY = RANDOM -OVERLAY_RANDOM_LINKS = %LINKS% -MAX_PARALLEL_SERVICE_CONNECTIONS=4000 -SETUP_TIMEOUT = 60 m - -[transport] -#MANIPULATE_DELAY_IN = 50 ms -MANIPULATE_DELAY_OUT = 10 ms - -[mesh] -REFRESH_CONNECTION_TIME = 1 h -DISABLE_TRY_CONNECT = YES -ID_ANNOUNCE_TIME = 240 s - -[dht] -FORCE_NSE = %NSE% diff --git a/src/mesh/run_profiler.sh b/src/mesh/run_profiler.sh deleted file mode 100755 index aba6ce4d4..000000000 --- a/src/mesh/run_profiler.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -if [ "$#" -lt "3" ]; then - echo "usage: $0 ROUND_TIME PEERS PINGING_PEERS"; - echo "example: $0 30s 16 1"; - exit 1; -fi - -ROUNDTIME=$1 -PEERS=$2 -PINGS=$3 - -if [ $PEERS -eq 1 ]; then - echo "cannot run 1 peer"; - exit 1; -fi - -LINKS=`echo "l($PEERS)/l(2) * $PEERS" | bc -l` -LINKS=`printf "%.0f" $LINKS` -NSE=`echo "l($PEERS)/l(2)" | bc -l` -echo "using $PEERS peers, $LINKS links"; - -sed -e "s/%LINKS%/$LINKS/;s/%NSE%/$NSE/" profiler.conf > .profiler.conf - -./gnunet-mesh-profiler $ROUNDTIME $PEERS $PINGS $4 |& tee log | grep -v DEBUG diff --git a/src/mesh/small.dat b/src/mesh/small.dat deleted file mode 100644 index c3805ee80..000000000 --- a/src/mesh/small.dat +++ /dev/null @@ -1,21 +0,0 @@ -16 -1:2 -1:9 -2:3 -3:4 -3:11 -4:5 -5:6 -5:13 -6:7 -7:8 -7:15 -8:9 -9:10 -10:11 -11:12 -12:13 -13:14 -14:15 -15:16 -16:1 diff --git a/src/mesh/test_cadet.c b/src/mesh/test_cadet.c deleted file mode 100644 index ac2661a86..000000000 --- a/src/mesh/test_cadet.c +++ /dev/null @@ -1,953 +0,0 @@ -/* - 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 cadet/test_cadet.c - * - * @brief Test for the cadet service: retransmission of traffic. - */ -#include -#include "platform.h" -#include "cadet_test_lib.h" -#include "gnunet_cadet_service.h" -#include "gnunet_statistics_service.h" -#include - - -/** - * How namy messages to send - */ -#define TOTAL_PACKETS 100 - -/** - * How long until we give up on connecting the peers? - */ -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) - -/** - * Time to wait for stuff that should be rather fast - */ -#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) - -/** - * DIFFERENT TESTS TO RUN - */ -#define SETUP 0 -#define FORWARD 1 -#define KEEPALIVE 2 -#define SPEED 3 -#define SPEED_ACK 4 -#define SPEED_REL 8 -#define P2P_SIGNAL 10 - -/** - * Which test are we running? - */ -static int test; - -/** - * String with test name - */ -char *test_name; - -/** - * Flag to send traffic leaf->root in speed tests to test BCK_ACK logic. - */ -static int test_backwards = GNUNET_NO; - -/** - * How many events have happened - */ -static int ok; - -/** - * Number of events expected to conclude the test successfully. - */ -int ok_goal; - -/** - * Size of each test packet - */ -size_t size_payload = sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t); - -/** - * Operation to get peer ids. - */ -struct GNUNET_TESTBED_Operation *t_op[2]; - -/** - * Peer ids. - */ -struct GNUNET_PeerIdentity *p_id[2]; - -/** - * Peer ids counter. - */ -unsigned int p_ids; - -/** - * Is the setup initialized? - */ -static int initialized; - -/** - * Number of payload packes sent - */ -static int data_sent; - -/** - * Number of payload packets received - */ -static int data_received; - -/** - * Number of payload packed explicitly (app level) acknowledged - */ -static int data_ack; - -/** - * Total number of currently running peers. - */ -static unsigned long long peers_running; - -/** - * Test context (to shut down). - */ -struct GNUNET_CADET_TEST_Context *test_ctx; - -/** - * Task called to disconnect peers. - */ -static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; - -/** - * Task To perform tests - */ -static GNUNET_SCHEDULER_TaskIdentifier test_task; - -/** - * Task called to shutdown test. - */ -static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; - -/** - * Cadet handle for the root peer - */ -static struct GNUNET_CADET_Handle *h1; - -/** - * Cadet handle for the first leaf peer - */ -static struct GNUNET_CADET_Handle *h2; - -/** - * Channel handle for the root peer - */ -static struct GNUNET_CADET_Channel *ch; - -/** - * Channel handle for the dest peer - */ -static struct GNUNET_CADET_Channel *incoming_ch; - -/** - * Time we started the data transmission (after channel has been established - * and initilized). - */ -static struct GNUNET_TIME_Absolute start_time; - -/** - * Peers handle. - */ -static struct GNUNET_TESTBED_Peer **testbed_peers; - -/** - * Statistics operation handle. - */ -static struct GNUNET_TESTBED_Operation *stats_op; - -/** - * Keepalives sent. - */ -static unsigned int ka_sent; - -/** - * Keepalives received. - */ -static unsigned int ka_received; - - -/** - * Show the results of the test (banwidth acheived) and log them to GAUGER - */ -static void -show_end_data (void) -{ - static struct GNUNET_TIME_Absolute end_time; - static struct GNUNET_TIME_Relative total_time; - - end_time = GNUNET_TIME_absolute_get(); - total_time = GNUNET_TIME_absolute_get_difference(start_time, end_time); - FPRINTF (stderr, "\nResults of test \"%s\"\n", test_name); - FPRINTF (stderr, "Test time %s\n", - GNUNET_STRINGS_relative_time_to_string (total_time, - GNUNET_YES)); - FPRINTF (stderr, "Test bandwidth: %f kb/s\n", - 4 * TOTAL_PACKETS * 1.0 / (total_time.rel_value_us / 1000)); // 4bytes * ms - FPRINTF (stderr, "Test throughput: %f packets/s\n\n", - TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000)); // packets * ms - GAUGER ("CADET", test_name, - TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000), - "packets/s"); -} - - -/** - * Shut down peergroup, clean up. - * - * @param cls Closure (unused). - * @param tc Task Context. - */ -static void -shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n"); - shutdown_handle = GNUNET_SCHEDULER_NO_TASK; -} - - -/** - * Disconnect from cadet services af all peers, call shutdown. - * - * @param cls Closure (unused). - * @param tc Task Context. - */ -static void -disconnect_cadet_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - long line = (long) cls; - unsigned int i; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "disconnecting cadet service of peers, called from line %ld\n", - line); - disconnect_task = GNUNET_SCHEDULER_NO_TASK; - for (i = 0; i < 2; i++) - { - GNUNET_TESTBED_operation_done (t_op[i]); - } - if (NULL != ch) - { - GNUNET_CADET_channel_destroy (ch); - ch = NULL; - } - if (NULL != incoming_ch) - { - GNUNET_CADET_channel_destroy (incoming_ch); - incoming_ch = NULL; - } - GNUNET_CADET_TEST_cleanup (test_ctx); - if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle) - { - GNUNET_SCHEDULER_cancel (shutdown_handle); - } - shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); -} - - -/** - * Abort test: schedule disconnect and shutdown immediately - * - * @param line Line in the code the abort is requested from (__LINE__). - */ -static void -abort_test (long line) -{ - if (disconnect_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (disconnect_task); - disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, - (void *) line); - } -} - -/** - * Transmit ready callback. - * - * @param cls Closure (message type). - * @param size Size of the tranmist buffer. - * @param buf Pointer to the beginning of the buffer. - * - * @return Number of bytes written to buf. - */ -static size_t -tmt_rdy (void *cls, size_t size, void *buf); - - -/** - * Task to schedule a new data transmission. - * - * @param cls Closure (peer #). - * @param tc Task Context. - */ -static void -data_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_CADET_TransmitHandle *th; - struct GNUNET_CADET_Channel *channel; - - if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0) - return; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data task\n"); - if (GNUNET_YES == test_backwards) - { - channel = incoming_ch; - } - else - { - channel = ch; - } - th = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO, - GNUNET_TIME_UNIT_FOREVER_REL, - size_payload, &tmt_rdy, (void *) 1L); - if (NULL == th) - { - unsigned long i = (unsigned long) cls; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Retransmission\n"); - if (0 == i) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, " in 1 ms\n"); - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, - &data_task, (void *)1UL); - } - else - { - i++; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "in %u ms\n", i); - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply( - GNUNET_TIME_UNIT_MILLISECONDS, - i), - &data_task, (void *)i); - } - } -} - - -/** - * Transmit ready callback - * - * @param cls Closure (message type). - * @param size Size of the buffer we have. - * @param buf Buffer to copy data to. - */ -size_t -tmt_rdy (void *cls, size_t size, void *buf) -{ - struct GNUNET_MessageHeader *msg = buf; - uint32_t *data; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "tmt_rdy called, filling buffer\n"); - if (size < size_payload || NULL == buf) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "size %u, buf %p, data_sent %u, data_received %u\n", - size, buf, data_sent, data_received); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ok %u, ok goal %u\n", ok, ok_goal); - GNUNET_break (ok >= ok_goal - 2); - - return 0; - } - msg->size = htons (size); - msg->type = htons ((long) cls); - data = (uint32_t *) &msg[1]; - *data = htonl (data_sent); - if (GNUNET_NO == initialized) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "sending initializer\n"); - } - else if (SPEED == test) - { - data_sent++; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - " Sent packet %d\n", data_sent); - if (data_sent < TOTAL_PACKETS) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - " Scheduling packet %d\n", data_sent + 1); - GNUNET_SCHEDULER_add_now (&data_task, NULL); - } - } - - return size_payload; -} - - -/** - * Function is called whenever a message is received. - * - * @param cls closure (set from GNUNET_CADET_connect) - * @param channel connection to the other end - * @param channel_ctx place to store local state associated with the channel - * @param message the actual message - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -int -data_callback (void *cls, struct GNUNET_CADET_Channel *channel, - void **channel_ctx, - const struct GNUNET_MessageHeader *message) -{ - long client = (long) cls; - long expected_target_client; - uint32_t *data; - - ok++; - - GNUNET_CADET_receive_done (channel); - - if ((ok % 20) == 0) - { - if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) - { - GNUNET_SCHEDULER_cancel (disconnect_task); - disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, - &disconnect_cadet_peers, - (void *) __LINE__); - } - } - - switch (client) - { - case 0L: - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message!\n"); - break; - case 4L: - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Leaf client %li got a message.\n", - client); - break; - default: - GNUNET_assert (0); - break; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: (%d/%d)\n", ok, ok_goal); - data = (uint32_t *) &message[1]; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, " payload: (%u)\n", ntohl (*data)); - if (SPEED == test && GNUNET_YES == test_backwards) - { - expected_target_client = 0L; - } - else - { - expected_target_client = 4L; - } - - if (GNUNET_NO == initialized) - { - initialized = GNUNET_YES; - start_time = GNUNET_TIME_absolute_get (); - if (SPEED == test) - { - GNUNET_assert (4L == client); - GNUNET_SCHEDULER_add_now (&data_task, NULL); - return GNUNET_OK; - } - } - - if (client == expected_target_client) // Normally 4 - { - data_received++; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received data %u\n", data_received); - if (SPEED != test || (ok_goal - 2) == ok) - { - GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO, - GNUNET_TIME_UNIT_FOREVER_REL, - size_payload, &tmt_rdy, (void *) 1L); - return GNUNET_OK; - } - else - { - if (data_received < TOTAL_PACKETS) - return GNUNET_OK; - } - } - else // Normally 0 - { - if (test == SPEED_ACK || test == SPEED) - { - data_ack++; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received ack %u\n", data_ack); - GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO, - GNUNET_TIME_UNIT_FOREVER_REL, - size_payload, &tmt_rdy, (void *) 1L); - if (data_ack < TOTAL_PACKETS && SPEED != test) - return GNUNET_OK; - if (ok == 2 && SPEED == test) - return GNUNET_OK; - show_end_data(); - } - if (test == P2P_SIGNAL) - { - GNUNET_CADET_channel_destroy (incoming_ch); - incoming_ch = NULL; - } - else - { - GNUNET_CADET_channel_destroy (ch); - ch = NULL; - } - } - - if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) - { - GNUNET_SCHEDULER_cancel (disconnect_task); - disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, - &disconnect_cadet_peers, - (void *) __LINE__); - } - - return GNUNET_OK; -} - - -/** - * Stats callback. Finish the stats testbed operation and when all stats have - * been iterated, shutdown the test. - * - * @param cls closure - * @param op the operation that has been finished - * @param emsg error message in case the operation has failed; will be NULL if - * operation has executed successfully. - */ -static void -stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "stats_cont for peer %u\n", cls); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, " sent: %u, received: %u\n", - ka_sent, ka_received); - if (ka_sent < 2 || ka_sent > ka_received + 1) - ok--; - GNUNET_TESTBED_operation_done (stats_op); - - if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) - GNUNET_SCHEDULER_cancel (disconnect_task); - disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, - (void *) __LINE__); - -} - - -/** - * Process statistic values. - * - * @param cls closure - * @param peer the peer the statistic belong to - * @param subsystem name of subsystem that created the statistic - * @param name the name of the datum - * @param value the current value - * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not - * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration - */ -static int -stats_iterator (void *cls, const struct GNUNET_TESTBED_Peer *peer, - const char *subsystem, const char *name, - uint64_t value, int is_persistent) -{ - static const char *s_sent = "# keepalives sent"; - static const char *s_recv = "# keepalives received"; - uint32_t i; - - i = GNUNET_TESTBED_get_index (peer); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %u - %s [%s]: %llu\n", - i, subsystem, name, value); - if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i) - ka_sent = value; - - if (0 == strncmp(s_recv, name, strlen (s_recv)) && 4 == i) - ka_received = value; - - return GNUNET_OK; -} - - -/** - * Task check that keepalives were sent and received. - * - * @param cls Closure (NULL). - * @param tc Task Context. - */ -static void -check_keepalives (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0) - return; - - disconnect_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "check keepalives\n"); - GNUNET_CADET_channel_destroy (ch); - stats_op = GNUNET_TESTBED_get_statistics (5, testbed_peers, - "cadet", NULL, - stats_iterator, stats_cont, NULL); -} - - -/** - * Handlers, for diverse services - */ -static struct GNUNET_CADET_MessageHandler handlers[] = { - {&data_callback, 1, sizeof (struct GNUNET_MessageHeader)}, - {NULL, 0, 0} -}; - - -/** - * Method called whenever another peer has added us to a channel - * the other peer initiated. - * - * @param cls Closure. - * @param channel New handle to the channel. - * @param initiator Peer that started the channel. - * @param port Port this channel is connected to. - * @param options channel option flags - * @return Initial channel context for the channel - * (can be NULL -- that's not an error). - */ -static void * -incoming_channel (void *cls, struct GNUNET_CADET_Channel *channel, - const struct GNUNET_PeerIdentity *initiator, - uint32_t port, enum GNUNET_CADET_ChannelOption options) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Incoming channel from %s to peer %d\n", - GNUNET_i2s (initiator), (long) cls); - ok++; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); - if ((long) cls == 4L) - incoming_ch = channel; - else - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Incoming channel for unknown client %lu\n", (long) cls); - GNUNET_break(0); - } - if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) - { - GNUNET_SCHEDULER_cancel (disconnect_task); - if (KEEPALIVE == test) - { - struct GNUNET_TIME_Relative delay; - delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS , 5); - disconnect_task = - GNUNET_SCHEDULER_add_delayed (delay, &check_keepalives, NULL); - } - else - disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, - &disconnect_cadet_peers, - (void *) __LINE__); - } - - return NULL; -} - -/** - * Function called whenever an inbound channel is destroyed. Should clean up - * any associated state. - * - * @param cls closure (set from GNUNET_CADET_connect) - * @param channel connection to the other end (henceforth invalid) - * @param channel_ctx place where local state associated - * with the channel is stored - */ -static void -channel_cleaner (void *cls, const struct GNUNET_CADET_Channel *channel, - void *channel_ctx) -{ - long i = (long) cls; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Incoming channel disconnected at peer %ld\n", i); - if (4L == i) - { - ok++; - GNUNET_break (channel == incoming_ch); - incoming_ch = NULL; - } - else if (0L == i) - { - if (P2P_SIGNAL == test) - { - ok ++; - } - GNUNET_break (channel == ch); - ch = NULL; - } - else - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Unknown peer! %d\n", i); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); - - if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) - { - GNUNET_SCHEDULER_cancel (disconnect_task); - disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, - (void *) __LINE__); - } - - return; -} - - -/** - * START THE TESTCASE ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES. - * - * Testcase continues when the root receives confirmation of connected peers, - * on callback funtion ch. - * - * @param cls Closure (unsued). - * @param tc Task Context. - */ -static void -do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - enum GNUNET_CADET_ChannelOption flags; - - if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0) - return; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test_task\n"); - - if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) - { - GNUNET_SCHEDULER_cancel (disconnect_task); - } - - flags = GNUNET_CADET_OPTION_DEFAULT; - if (SPEED_REL == test) - { - test = SPEED; - flags |= GNUNET_CADET_OPTION_RELIABLE; - } - ch = GNUNET_CADET_channel_create (h1, NULL, p_id[1], 1, flags); - - disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, - &disconnect_cadet_peers, - (void *) __LINE__); - if (KEEPALIVE == test) - return; /* Don't send any data. */ - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending data initializer...\n"); - data_ack = 0; - data_received = 0; - data_sent = 0; - GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO, - GNUNET_TIME_UNIT_FOREVER_REL, - size_payload, &tmt_rdy, (void *) 1L); -} - -/** - * Callback to be called when the requested peer information is available - * - * @param cls the closure from GNUNET_TESTBED_peer_get_information() - * @param op the operation this callback corresponds to - * @param pinfo the result; will be NULL if the operation has failed - * @param emsg error message if the operation has failed; - * NULL if the operation is successfull - */ -static void -pi_cb (void *cls, - struct GNUNET_TESTBED_Operation *op, - const struct GNUNET_TESTBED_PeerInformation *pinfo, - const char *emsg) -{ - long i = (long) cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "id callback for %ld\n", i); - - if (NULL == pinfo || NULL != emsg) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg); - abort_test (__LINE__); - return; - } - p_id[i] = pinfo->result.id; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " id: %s\n", GNUNET_i2s (p_id[i])); - p_ids++; - if (p_ids < 2) - return; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n"); - test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, - &do_test, NULL); -} - -/** - * test main: start test when all peers are connected - * - * @param cls Closure. - * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end. - * @param num_peers Number of peers that are running. - * @param peers Array of peers. - * @param cadetes Handle to each of the CADETs of the peers. - */ -static void -tmain (void *cls, - struct GNUNET_CADET_TEST_Context *ctx, - unsigned int num_peers, - struct GNUNET_TESTBED_Peer **peers, - struct GNUNET_CADET_Handle **cadetes) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n"); - ok = 0; - test_ctx = ctx; - peers_running = num_peers; - testbed_peers = peers; - h1 = cadetes[0]; - h2 = cadetes[num_peers - 1]; - disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, - &disconnect_cadet_peers, - (void *) __LINE__); - shutdown_handle = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, - &shutdown_task, NULL); - t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0], - GNUNET_TESTBED_PIT_IDENTITY, - &pi_cb, (void *) 0L); - t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1], - GNUNET_TESTBED_PIT_IDENTITY, - &pi_cb, (void *) 1L); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n"); -} - - -/** - * Main: start test - */ -int -main (int argc, char *argv[]) -{ - initialized = GNUNET_NO; - static uint32_t ports[2]; - const char *config_file; - - GNUNET_log_setup ("test", "DEBUG", NULL); - config_file = "test_cadet.conf"; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start\n"); - if (strstr (argv[0], "_cadet_forward") != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "FORWARD\n"); - test = FORWARD; - test_name = "unicast"; - ok_goal = 4; - } - else if (strstr (argv[0], "_cadet_signal") != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SIGNAL\n"); - test = P2P_SIGNAL; - test_name = "signal"; - ok_goal = 4; - } - else if (strstr (argv[0], "_cadet_speed_ack") != NULL) - { - /* Test is supposed to generate the following callbacks: - * 1 incoming channel (@dest) - * TOTAL_PACKETS received data packet (@dest) - * TOTAL_PACKETS received data packet (@orig) - * 1 received channel destroy (@dest) - */ - ok_goal = TOTAL_PACKETS * 2 + 2; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n"); - test = SPEED_ACK; - test_name = "speed ack"; - } - else if (strstr (argv[0], "_cadet_speed") != NULL) - { - /* Test is supposed to generate the following callbacks: - * 1 incoming channel (@dest) - * 1 initial packet (@dest) - * TOTAL_PACKETS received data packet (@dest) - * 1 received data packet (@orig) - * 1 received channel destroy (@dest) - */ - ok_goal = TOTAL_PACKETS + 4; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n"); - if (strstr (argv[0], "_reliable") != NULL) - { - test = SPEED_REL; - test_name = "speed reliable"; - config_file = "test_cadet_drop.conf"; - } - else - { - test = SPEED; - test_name = "speed"; - } - } - else if (strstr (argv[0], "_keepalive") != NULL) - { - test = KEEPALIVE; - /* Test is supposed to generate the following callbacks: - * 1 incoming channel (@dest) - * [wait] - * 1 received channel destroy (@dest) - */ - ok_goal = 2; - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNKNOWN\n"); - test = SETUP; - ok_goal = 0; - } - - if (strstr (argv[0], "backwards") != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "BACKWARDS (LEAF TO ROOT)\n"); - test_backwards = GNUNET_YES; - GNUNET_asprintf (&test_name, "backwards %s", test_name); - } - - p_ids = 0; - ports[0] = 1; - ports[1] = 0; - GNUNET_CADET_TEST_run ("test_cadet_small", - config_file, - 5, - &tmain, - NULL, /* tmain cls */ - &incoming_channel, - &channel_cleaner, - handlers, - ports); - - if (ok_goal > ok) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "FAILED! (%d/%d)\n", ok, ok_goal); - return 1; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n"); - return 0; -} - -/* end of test_cadet.c */ - diff --git a/src/mesh/test_cadet.conf b/src/mesh/test_cadet.conf deleted file mode 100644 index 5a2f03dd0..000000000 --- a/src/mesh/test_cadet.conf +++ /dev/null @@ -1,100 +0,0 @@ -[testbed] -AUTOSTART = NO -PORT = 12113 -ACCEPT_FROM = 127.0.0.1; -HOSTNAME = localhost -OVERLAY_TOPOLOGY = LINE -#PREFIX = xterm -geometry 100x85 -T peer1 -e libtool --mode=execute gdb --args - -[fs] -AUTOSTART = NO - -[resolver] -AUTOSTART = NO - -[mesh] -#BINARY = gnunet-service-mesh-enc -#PREFIX = valgrind --leak-check=full -#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args -AUTOSTART = NO -ACCEPT_FROM = 127.0.0.1; -REFRESH_CONNECTION_TIME = 2 s -ID_ANNOUNCE_TIME = 5 s -CONNECT_TIMEOUT = 30 s -DEFAULT_TTL = 16 -DHT_REPLICATION_LEVEL = 10 -MAX_TUNNELS = 10 -MAX_CONNECTIONS = 10 -MAX_MSGS_QUEUE = 20 -DISABLE_TRY_CONNECT = YES - -[dht] -AUTOSTART = NO -DISABLE_TRY_CONNECT = YES -FORCE_NSE = 3 - -[dhtcache] -QUOTA = 1 MB -DATABASE = heap - -[transport] -PLUGINS = udp -ACCEPT_FROM6 = ::1; -ACCEPT_FROM = 127.0.0.1; -NEIGHBOUR_LIMIT = 50 -PORT = 12365 -#MANIPULATE_DELAY_IN = 10 ms -#MANIPULATE_DELAY_OUT = 10 ms - - -[ats] -WAN_QUOTA_OUT = 3932160 -WAN_QUOTA_IN = 3932160 - -[core] -PORT = 12092 -AUTOSTART = YES -USE_EPHEMERAL_KEYS = NO - -[arm] -DEFAULTSERVICES = core transport dht mesh statistics -PORT = 12366 - -[transport-udp] -TIMEOUT = 300 s -PORT = 12368 - -[gnunetd] -HOSTKEY = $GNUNET_TEST_HOME/.hostkey - -[PATHS] -GNUNET_TEST_HOME = /tmp/test-mesh/ - -[dns] -AUTOSTART = NO - -[nse] -AUTOSTART = NO - -[vpn] -AUTOSTART = NO - -[nat] -RETURN_LOCAL_ADDRESSES = YES -DISABLEV6 = YES -USE_LOCALADDR = YES - -[gns-helper-service-w32] -AUTOSTART = NO - -[consensus] -AUTOSTART = NO - -[gns] -AUTOSTART = NO - -[statistics] -AUTOSTART = NO - -[peerinfo] -NO_IO = YES diff --git a/src/mesh/test_cadet_drop.conf b/src/mesh/test_cadet_drop.conf deleted file mode 100644 index 4df0e3f34..000000000 --- a/src/mesh/test_cadet_drop.conf +++ /dev/null @@ -1,4 +0,0 @@ -@INLINE@ test_mesh.conf - -[mesh] -DROP_PERCENT = 1 diff --git a/src/mesh/test_cadet_local.c b/src/mesh/test_cadet_local.c deleted file mode 100644 index 0796aaf12..000000000 --- a/src/mesh/test_cadet_local.c +++ /dev/null @@ -1,337 +0,0 @@ -/* - 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 cadet/test_cadet_local.c - * @brief test cadet local: test of cadet channels with just one peer - * @author Bartlomiej Polot - */ - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_dht_service.h" -#include "gnunet_testing_lib.h" -#include "gnunet_cadet_service.h" - -struct GNUNET_TESTING_Peer *me; - -static struct GNUNET_CADET_Handle *cadet_peer_1; - -static struct GNUNET_CADET_Handle *cadet_peer_2; - -static struct GNUNET_CADET_Channel *ch; - -static int result = GNUNET_OK; - -static int got_data = GNUNET_NO; - -static GNUNET_SCHEDULER_TaskIdentifier abort_task; - -static GNUNET_SCHEDULER_TaskIdentifier shutdown_task; - -static struct GNUNET_CADET_TransmitHandle *mth; - - -/** - * Connect to other client and send data - * - * @param cls Closue (unused). - * @param tc TaskContext. - */ -static void -do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - - -/** - * Shutdown nicely - */ -static void -do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutdown\n"); - if (GNUNET_SCHEDULER_NO_TASK != abort_task) - { - GNUNET_SCHEDULER_cancel (abort_task); - } - if (NULL != ch) - { - GNUNET_CADET_channel_destroy (ch); - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect client 1\n"); - if (NULL != cadet_peer_1) - { - GNUNET_CADET_disconnect (cadet_peer_1); - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect client 2\n"); - if (NULL != cadet_peer_2) - { - GNUNET_CADET_disconnect (cadet_peer_2); - } -} - - -/** - * Something went wrong and timed out. Kill everything and set error flag - */ -static void -do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ABORT\n"); - result = GNUNET_SYSERR; - abort_task = GNUNET_SCHEDULER_NO_TASK; - if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) - { - GNUNET_SCHEDULER_cancel (shutdown_task); - shutdown_task = GNUNET_SCHEDULER_NO_TASK; - } - do_shutdown (cls, tc); -} - - -/** - * Function is called whenever a message is received. - * - * @param cls closure (set from GNUNET_CADET_connect) - * @param channel connection to the other end - * @param channel_ctx place to store local state associated with the channel - * @param message the actual message - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -static int -data_callback (void *cls, struct GNUNET_CADET_Channel *channel, - void **channel_ctx, - const struct GNUNET_MessageHeader *message) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data callback! Shutting down.\n"); - got_data = GNUNET_YES; - if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) - GNUNET_SCHEDULER_cancel (shutdown_task); - shutdown_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_shutdown, - NULL); - GNUNET_CADET_receive_done (channel); - return GNUNET_OK; -} - - -/** - * Method called whenever another peer has added us to a channel - * the other peer initiated. - * - * @param cls closure - * @param channel new handle to the channel - * @param initiator peer that started the channel - * @param port port number - * @param options channel options - * @return initial channel context for the channel - * (can be NULL -- that's not an error) - */ -static void * -inbound_channel (void *cls, struct GNUNET_CADET_Channel *channel, - const struct GNUNET_PeerIdentity *initiator, - uint32_t port, enum GNUNET_CADET_ChannelOption options) -{ - long id = (long) cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "received incoming channel on peer %d, port %u\n", - id, port); - if (id != 2L) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "wrong peer\n"); - result = GNUNET_SYSERR; - } - return NULL; -} - - -/** - * Function called whenever an channel is destroyed. Should clean up - * any associated state. - * - * @param cls closure (set from GNUNET_CADET_connect) - * @param channel connection to the other end (henceforth invalid) - * @param channel_ctx place where local state associated - * with the channel is stored - */ -static void -channel_end (void *cls, const struct GNUNET_CADET_Channel *channel, - void *channel_ctx) -{ - long id = (long) cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "incoming channel closed at peer %ld\n", - id); - if (NULL != mth) - { - GNUNET_CADET_notify_transmit_ready_cancel (mth); - mth = NULL; - } - if (GNUNET_NO == got_data) - { - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply ( - GNUNET_TIME_UNIT_SECONDS, - 2), - &do_connect, NULL); - } -} - - -/** - * Handler array for traffic received on peer1 - */ -static struct GNUNET_CADET_MessageHandler handlers1[] = { - {&data_callback, 1, 0}, - {NULL, 0, 0} -}; - - -/** - * Handler array for traffic received on peer2 (none expected) - */ -static struct GNUNET_CADET_MessageHandler handlers2[] = { - {&data_callback, 1, 0}, - {NULL, 0, 0} -}; - - -/** - * Data send callback: fillbuffer with test packet. - * - * @param cls Closure (unused). - * @param size Buffer size. - * @param buf Buffer to fill. - * - * @return size of test packet. - */ -static size_t -do_send (void *cls, size_t size, void *buf) -{ - struct GNUNET_MessageHeader *m = buf; - - mth = NULL; - if (NULL == buf) - { - GNUNET_break (0); - result = GNUNET_SYSERR; - return 0; - } - m->size = htons (sizeof (struct GNUNET_MessageHeader)); - m->type = htons (1); - GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); - return sizeof (struct GNUNET_MessageHeader); -} - -/** - * Connect to other client and send data - * - * @param cls Closue (unused). - * @param tc TaskContext. - */ -static void -do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_PeerIdentity id; - - if (NULL != tc && 0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) - return; - - GNUNET_TESTING_peer_get_identity (me, &id); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CONNECT BY PORT\n"); - ch = GNUNET_CADET_channel_create (cadet_peer_1, NULL, &id, 1, - GNUNET_CADET_OPTION_DEFAULT); - mth = GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO, - GNUNET_TIME_UNIT_FOREVER_REL, - sizeof (struct GNUNET_MessageHeader), - &do_send, NULL); -} - - -/** - * Initialize framework and start test - * - * @param cls Closure (unused). - * @param cfg Configuration handle. - * @param peer Testing peer handle. - */ -static void -run (void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Peer *peer) -{ - static uint32_t ports[] = {1, 0}; - - me = peer; - abort_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 15), &do_abort, - NULL); - cadet_peer_1 = GNUNET_CADET_connect (cfg, /* configuration */ - (void *) 1L, /* cls */ - NULL, /* inbound new hndlr */ - &channel_end, /* channel end hndlr */ - handlers1, /* traffic handlers */ - NULL); /* ports offered */ - - cadet_peer_2 = GNUNET_CADET_connect (cfg, /* configuration */ - (void *) 2L, /* cls */ - &inbound_channel, /* inbound new hndlr */ - &channel_end, /* channel end hndlr */ - handlers2, /* traffic handlers */ - ports); /* ports offered */ - if (NULL == cadet_peer_1 || NULL == cadet_peer_2) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Couldn't connect to cadet :(\n"); - result = GNUNET_SYSERR; - return; - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "YAY! CONNECTED TO CADET :D\n"); - } - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply ( - GNUNET_TIME_UNIT_SECONDS, - 2), - &do_connect, NULL); -} - - -/** - * Main - */ -int -main (int argc, char *argv[]) -{ - if (0 != GNUNET_TESTING_peer_run ("test-cadet-local", - "test_cadet.conf", - &run, NULL)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "run failed\n"); - return 2; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Final result: %d\n", result); - return (result == GNUNET_OK) ? 0 : 1; -} - -/* end of test_cadet_local_1.c */ diff --git a/src/mesh/test_cadet_single.c b/src/mesh/test_cadet_single.c deleted file mode 100644 index 3780c745c..000000000 --- a/src/mesh/test_cadet_single.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - 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 cadet/test_cadet_single.c - * @brief test cadet single: test of cadet channels with just one client - * @author Bartlomiej Polot - */ - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_dht_service.h" -#include "gnunet_testing_lib.h" -#include "gnunet_cadet_service.h" - -#define REPETITIONS 5 -#define DATA_SIZE 35000 - -struct GNUNET_TESTING_Peer *me; - -static struct GNUNET_CADET_Handle *cadet; - -static struct GNUNET_CADET_Channel *ch1; - -static struct GNUNET_CADET_Channel *ch2; - -static int result; - -static GNUNET_SCHEDULER_TaskIdentifier abort_task; - -static GNUNET_SCHEDULER_TaskIdentifier shutdown_task; - -static unsigned int repetition; - - -/* forward declaration */ -static size_t -do_send (void *cls, size_t size, void *buf); - - -/** - * Shutdown nicely - */ -static void -do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutdown\n"); - if (GNUNET_SCHEDULER_NO_TASK != abort_task) - { - GNUNET_SCHEDULER_cancel (abort_task); - } - if (NULL != ch1) - { - GNUNET_CADET_channel_destroy (ch1); - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect client 1\n"); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect client 2\n"); - if (NULL != cadet) - { - GNUNET_CADET_disconnect (cadet); - cadet = NULL; - } - else - { - GNUNET_break (0); - } -} - - -/** - * Something went wrong and timed out. Kill everything and set error flag - */ -static void -do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ABORT\n"); - result = GNUNET_SYSERR; - abort_task = GNUNET_SCHEDULER_NO_TASK; - if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) - { - GNUNET_SCHEDULER_cancel (shutdown_task); - shutdown_task = GNUNET_SCHEDULER_NO_TASK; - } - do_shutdown (cls, tc); -} - - -static void -finish (void) -{ - if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) - GNUNET_SCHEDULER_cancel (shutdown_task); - shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, - &do_shutdown, NULL); -} - - -/** - * Function is called whenever a message is received. - * - * @param cls closure (set from GNUNET_CADET_connect) - * @param channel connection to the other end - * @param channel_ctx place to store local state associated with the channel - * @param message the actual message - * - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -static int -data_callback (void *cls, struct GNUNET_CADET_Channel *channel, - void **channel_ctx, - const struct GNUNET_MessageHeader *message) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Data callback! Repetition %u/%u\n", - repetition, REPETITIONS); - repetition = repetition + 1; - if (repetition < REPETITIONS) - { - struct GNUNET_CADET_Channel *my_channel; - if (repetition % 2 == 0) - my_channel = ch1; - else - my_channel = ch2; - GNUNET_CADET_notify_transmit_ready (my_channel, GNUNET_NO, - GNUNET_TIME_UNIT_FOREVER_REL, - sizeof (struct GNUNET_MessageHeader) - + DATA_SIZE, - &do_send, NULL); - GNUNET_CADET_receive_done (channel); - return GNUNET_OK; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All data OK. Destroying channel.\n"); - GNUNET_CADET_channel_destroy (ch1); - ch1 = NULL; - return GNUNET_OK; -} - - -/** - * Method called whenever another peer has added us to a channel - * the other peer initiated. - * - * @param cls closure - * @param channel new handle to the channel - * @param initiator peer that started the channel - * @param port port number - * @param options channel option flags - * @return initial channel context for the channel - * (can be NULL -- that's not an error) - */ -static void * -inbound_channel (void *cls, struct GNUNET_CADET_Channel *channel, - const struct GNUNET_PeerIdentity *initiator, - uint32_t port, enum GNUNET_CADET_ChannelOption options) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "received incoming channel on port %u\n", - port); - ch2 = channel; - return NULL; -} - - -/** - * Function called whenever an inbound channel is destroyed. Should clean up - * any associated state. - * - * @param cls closure (set from GNUNET_CADET_connect) - * @param channel connection to the other end (henceforth invalid) - * @param channel_ctx place where local state associated - * with the channel is stored - */ -static void -channel_end (void *cls, const struct GNUNET_CADET_Channel *channel, - void *channel_ctx) -{ - long id = (long) cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "incoming channel closed at peer %ld\n", - id); - if (REPETITIONS == repetition && channel == ch2) - { - ch2 = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "everything fine! finishing!\n"); - result = GNUNET_OK; - finish (); - } -} - - -/** - * Handler array for traffic received on peer1 - */ -static struct GNUNET_CADET_MessageHandler handlers1[] = { - {&data_callback, 1, 0}, - {NULL, 0, 0} -}; - - -/** - * Data send callback: fillbuffer with test packet. - * - * @param cls Closure (unused). - * @param size Buffer size. - * @param buf Buffer to fill. - * - * @return size of test packet. - */ -static size_t -do_send (void *cls, size_t size, void *buf) -{ - struct GNUNET_MessageHeader *m = buf; - - if (NULL == buf) - { - GNUNET_break (0); - result = GNUNET_SYSERR; - return 0; - } - m->size = htons (sizeof (struct GNUNET_MessageHeader)); - m->type = htons (1); - memset (&m[1], 0, DATA_SIZE); - GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader) + DATA_SIZE); - return sizeof (struct GNUNET_MessageHeader) + DATA_SIZE; -} - -/** - * Connect to other client and send data - * - * @param cls Closue (unused). - * @param tc TaskContext. - */ -static void -do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_PeerIdentity id; - size_t size = sizeof (struct GNUNET_MessageHeader) + DATA_SIZE; - - if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0) - return; - - GNUNET_TESTING_peer_get_identity (me, &id); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CONNECT BY PORT\n"); - ch1 = GNUNET_CADET_channel_create (cadet, NULL, &id, 1, - GNUNET_CADET_OPTION_DEFAULT); - GNUNET_CADET_notify_transmit_ready (ch1, GNUNET_NO, - GNUNET_TIME_UNIT_FOREVER_REL, - size, &do_send, NULL); -} - - -/** - * Initialize framework and start test - * - * @param cls Closure (unused). - * @param cfg Configuration handle. - * @param peer Testing peer handle. - */ -static void -run (void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Peer *peer) -{ - static uint32_t ports[] = {1, 0}; - - me = peer; - abort_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 15), &do_abort, - NULL); - cadet = GNUNET_CADET_connect (cfg, /* configuration */ - (void *) 1L, /* cls */ - &inbound_channel, /* inbound new hndlr */ - &channel_end, /* inbound end hndlr */ - handlers1, /* traffic handlers */ - ports); /* ports offered */ - - if (NULL == cadet) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Couldn't connect to cadet :(\n"); - result = GNUNET_SYSERR; - return; - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "YAY! CONNECTED TO CADET :D\n"); - } - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_connect, NULL); -} - - -/** - * Main - */ -int -main (int argc, char *argv[]) -{ - result = GNUNET_NO; - if (0 != GNUNET_TESTING_peer_run ("test-cadet-local", - "test_cadet.conf", - &run, NULL)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "run failed\n"); - return 2; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Final result: %d\n", result); - return (result == GNUNET_OK) ? 0 : 1; -} - -/* end of test_cadet_single.c */ diff --git a/src/mesh/valgrind-mesh.supp b/src/mesh/valgrind-mesh.supp deleted file mode 100644 index fecd5185b..000000000 --- a/src/mesh/valgrind-mesh.supp +++ /dev/null @@ -1,116 +0,0 @@ -{ - logsetup_addr - Memcheck:Addr8 - obj:/lib/libc-2.14.1.so - ... - fun:get_type - fun:GNUNET_log_setup - fun:GNUNET_SERVICE_run - fun:main -} - -{ - scanf_addr - Memcheck:Addr8 - obj:/lib/libc-2.14.1.so - ... - fun:vsscanf - fun:sscanf - fun:GNUNET_CONFIGURATION_get_value_number - fun:GNUNET_SERVICE_get_server_addresses - fun:setup_service - fun:GNUNET_SERVICE_run - fun:main -} - -{ - mylog_addr - Memcheck:Addr8 - obj:/lib/libc-2.14.1.so - ... - fun:service_task - fun:GNUNET_SCHEDULER_run - fun:GNUNET_SERVICE_run - fun:main -} - -{ - mylog_uninit - Memcheck:Value8 - obj:/lib/libc-2.14.1.so - ... - fun:mylog - fun:GNUNET_log_from_nocheck - fun:service_task - ... - fun:GNUNET_SCHEDULER_run - fun:GNUNET_SERVICE_run - fun:main -} - -{ - mylog_from_cond - Memcheck:Cond - obj:/lib/libc-2.14.1.so - ... - fun:mylog - fun:GNUNET_log_from_nocheck - ... - fun:service_task - fun:GNUNET_SCHEDULER_run - fun:GNUNET_SERVICE_run - fun:main -} - -{ - mylog_cond - Memcheck:Cond - obj:/lib/libc-2.14.1.so - ... - fun:mylog - fun:GNUNET_log_nocheck - ... - fun:service_task - fun:GNUNET_SCHEDULER_run - fun:GNUNET_SERVICE_run - fun:main -} - -{ - inet_ntop_cond - Memcheck:Cond - obj:/lib/libc-2.14.1.so - ... - fun:inet_ntop - fun:GNUNET_a2s - ... - fun:service_task - fun:GNUNET_SCHEDULER_run - fun:GNUNET_SERVICE_run - fun:main -} - -{ - create_key_from_file - Memcheck:Addr8 - obj:/lib/libc-2.14.1.so - ... - fun:GNUNET_CRYPTO_rsa_key_create_from_file - fun:run - fun:service_task - fun:GNUNET_SCHEDULER_run - fun:GNUNET_SERVICE_run - fun:main -} - -{ - main_notify_handler - Memcheck:Addr8 - obj:/lib/libc-2.14.1.so - ... - fun:main_notify_handler - fun:receive_ready - fun:GNUNET_SCHEDULER_run - fun:GNUNET_SERVICE_run - fun:main -} \ No newline at end of file -- cgit v1.2.3