aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arm/gnunet-service-arm.c1
-rw-r--r--src/cadet/Makefile.am208
-rw-r--r--src/cadet/cadet.conf.in2
-rw-r--r--src/cadet/cadet.h2
-rw-r--r--src/cadet/cadet_path.c363
-rw-r--r--src/cadet/cadet_path.h226
-rw-r--r--src/cadet/cadet_protocol.h150
-rw-r--r--src/cadet/cadet_test_lib.c135
-rw-r--r--src/cadet/cadet_test_lib.h40
-rw-r--r--src/cadet/cadet_test_lib_new.c362
-rw-r--r--src/cadet/cadet_test_lib_new.h106
-rw-r--r--src/cadet/gnunet-service-cadet-new.c1496
-rw-r--r--src/cadet/gnunet-service-cadet-new_channel.c2040
-rw-r--r--src/cadet/gnunet-service-cadet-new_channel.h262
-rw-r--r--src/cadet/gnunet-service-cadet-new_connection.c1093
-rw-r--r--src/cadet/gnunet-service-cadet-new_connection.h339
-rw-r--r--src/cadet/gnunet-service-cadet-new_dht.c351
-rw-r--r--src/cadet/gnunet-service-cadet-new_dht.h100
-rw-r--r--src/cadet/gnunet-service-cadet-new_hello.c152
-rw-r--r--src/cadet/gnunet-service-cadet-new_hello.h80
-rw-r--r--src/cadet/gnunet-service-cadet-new_peer.c1478
-rw-r--r--src/cadet/gnunet-service-cadet-new_peer.h394
-rw-r--r--src/cadet/gnunet-service-cadet.c1470
-rw-r--r--src/cadet/gnunet-service-cadet.h (renamed from src/cadet/gnunet-service-cadet-new.h)2
-rw-r--r--src/cadet/gnunet-service-cadet_channel.c3461
-rw-r--r--src/cadet/gnunet-service-cadet_channel.h387
-rw-r--r--src/cadet/gnunet-service-cadet_connection.c4010
-rw-r--r--src/cadet/gnunet-service-cadet_connection.h605
-rw-r--r--src/cadet/gnunet-service-cadet_core.c (renamed from src/cadet/gnunet-service-cadet-new_core.c)10
-rw-r--r--src/cadet/gnunet-service-cadet_core.h (renamed from src/cadet/gnunet-service-cadet-new_core.h)0
-rw-r--r--src/cadet/gnunet-service-cadet_dht.c373
-rw-r--r--src/cadet/gnunet-service-cadet_dht.h49
-rw-r--r--src/cadet/gnunet-service-cadet_hello.c140
-rw-r--r--src/cadet/gnunet-service-cadet_hello.h5
-rw-r--r--src/cadet/gnunet-service-cadet_local.c1553
-rw-r--r--src/cadet/gnunet-service-cadet_local.h234
-rw-r--r--src/cadet/gnunet-service-cadet_paths.c (renamed from src/cadet/gnunet-service-cadet-new_paths.c)10
-rw-r--r--src/cadet/gnunet-service-cadet_paths.h (renamed from src/cadet/gnunet-service-cadet-new_paths.h)2
-rw-r--r--src/cadet/gnunet-service-cadet_peer.c2928
-rw-r--r--src/cadet/gnunet-service-cadet_peer.h519
-rw-r--r--src/cadet/gnunet-service-cadet_tunnel.c3501
-rw-r--r--src/cadet/gnunet-service-cadet_tunnel.h616
-rw-r--r--src/cadet/gnunet-service-cadet_tunnels.c (renamed from src/cadet/gnunet-service-cadet-new_tunnels.c)13
-rw-r--r--src/cadet/gnunet-service-cadet_tunnels.h (renamed from src/cadet/gnunet-service-cadet-new_tunnels.h)4
-rw-r--r--src/cadet/test_cadet.c795
-rw-r--r--src/cadet/test_cadet_local.c351
-rw-r--r--src/cadet/test_cadet_new.c1105
-rw-r--r--src/cadet/test_cadet_single.c354
-rw-r--r--src/datacache/Makefile.am1
-rw-r--r--src/datacache/plugin_datacache_sqlite.c549
-rw-r--r--src/datastore/plugin_datastore_sqlite.c714
-rw-r--r--src/include/gnunet_sq_lib.h11
-rw-r--r--src/revocation/test_revocation.c20
-rw-r--r--src/set/Makefile.am2
-rw-r--r--src/set/gnunet-service-set.c284
-rw-r--r--src/set/gnunet-service-set.h50
-rw-r--r--src/set/gnunet-service-set_intersection.c139
-rw-r--r--src/set/gnunet-service-set_union.c682
-rw-r--r--src/set/set_api.c12
-rw-r--r--src/set/test_set_union_copy.c1
-rw-r--r--src/sq/sq.c25
-rw-r--r--src/sq/sq_query_helper.c44
-rw-r--r--src/sq/sq_result_helper.c67
63 files changed, 7516 insertions, 26962 deletions
diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c
index 4f3e964e31..cc23ef1f68 100644
--- a/src/arm/gnunet-service-arm.c
+++ b/src/arm/gnunet-service-arm.c
@@ -812,6 +812,7 @@ start_process (struct ServiceList *sl,
"%s %s",
fin_options,
optpos);
+ GNUNET_free (fin_options);
GNUNET_free (optpos);
}
else
diff --git a/src/cadet/Makefile.am b/src/cadet/Makefile.am
index b52079b2e1..1fe9123057 100644
--- a/src/cadet/Makefile.am
+++ b/src/cadet/Makefile.am
@@ -23,7 +23,6 @@ AM_CLFAGS = -g
libexec_PROGRAMS = \
gnunet-service-cadet \
- gnunet-service-cadet-new \
$(EXP_LIBEXEC)
bin_PROGRAMS = \
@@ -61,88 +60,40 @@ gnunet_cadet_LDADD = \
libgnunetcadetnew.la \
$(top_builddir)/src/util/libgnunetutil.la
-gnunet_service_cadet_new_SOURCES = \
- gnunet-service-cadet-new.c gnunet-service-cadet-new.h \
- gnunet-service-cadet-new_channel.c gnunet-service-cadet-new_channel.h \
- gnunet-service-cadet-new_connection.c gnunet-service-cadet-new_connection.h \
- gnunet-service-cadet-new_core.c gnunet-service-cadet-new_core.h \
- gnunet-service-cadet-new_dht.c gnunet-service-cadet-new_dht.h \
- gnunet-service-cadet-new_hello.c gnunet-service-cadet-new_hello.h \
- gnunet-service-cadet-new_tunnels.c gnunet-service-cadet-new_tunnels.h \
- gnunet-service-cadet-new_paths.c gnunet-service-cadet-new_paths.h \
- gnunet-service-cadet-new_peer.c gnunet-service-cadet-new_peer.h
-gnunet_service_cadet_new_LDADD = \
- $(top_builddir)/src/util/libgnunetutil.la \
- $(top_builddir)/src/ats/libgnunetats.la \
- $(top_builddir)/src/core/libgnunetcore.la \
- $(top_builddir)/src/dht/libgnunetdht.la \
- $(top_builddir)/src/statistics/libgnunetstatistics.la \
- $(top_builddir)/src/transport/libgnunettransport.la \
- $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
- $(top_builddir)/src/hello/libgnunethello.la \
- $(top_builddir)/src/block/libgnunetblock.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.c gnunet-service-cadet.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_connection.c gnunet-service-cadet_connection.h \
+ gnunet-service-cadet_core.c gnunet-service-cadet_core.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_tunnels.c gnunet-service-cadet_tunnels.h \
+ gnunet-service-cadet_paths.c gnunet-service-cadet_paths.h \
+ gnunet-service-cadet_peer.c gnunet-service-cadet_peer.h
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/ats/libgnunetats.la \
+ $(top_builddir)/src/core/libgnunetcore.la \
$(top_builddir)/src/dht/libgnunetdht.la \
$(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/transport/libgnunettransport.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
+ gnunet_service_cadet_new_LDFLAGS = -lrt
endif
if HAVE_TESTING
- noinst_LTLIBRARIES = libgnunetcadettest.la libgnunetcadettestnew.la $(noinst_LIB_EXP)
- noinst_PROGRAMS = gnunet-cadet-profiler
+ noinst_LTLIBRARIES = libgnunetcadettest.la $(noinst_LIB_EXP)
+# noinst_PROGRAMS = gnunet-cadet-profiler
endif
-libgnunetcadettest_la_SOURCES = \
- cadet_test_lib.c cadet_test_lib.h
-libgnunetcadettest_la_LIBADD = \
- $(top_builddir)/src/util/libgnunetutil.la \
- $(top_builddir)/src/testbed/libgnunettestbed.la \
- libgnunetcadet.la
-
if HAVE_TESTING
check_PROGRAMS = \
test_cadet_local_mq \
- test_cadet_2_forward_new \
- test_cadet_2_forward_new \
- test_cadet_2_signal_new \
- test_cadet_2_keepalive_new \
- test_cadet_2_speed_new \
- test_cadet_2_speed_ack_new \
- test_cadet_2_speed_backwards_new \
- test_cadet_2_speed_reliable_new \
- test_cadet_2_speed_reliable_backwards_new \
- test_cadet_5_forward_new \
- test_cadet_5_signal_new \
- test_cadet_5_keepalive_new \
- test_cadet_5_speed_new \
- test_cadet_5_speed_ack_new \
- test_cadet_5_speed_reliable_new \
- test_cadet_5_speed_reliable_backwards_new \
- test_cadet_5_speed_backwards_new \
- test_cadet_single \
- test_cadet_local \
+ test_cadet_2_forward \
test_cadet_2_forward \
test_cadet_2_signal \
test_cadet_2_keepalive \
@@ -161,32 +112,10 @@ check_PROGRAMS = \
test_cadet_5_speed_backwards
endif
-ld_cadet_test_lib = \
- $(top_builddir)/src/util/libgnunetutil.la \
- $(top_builddir)/src/testing/libgnunettesting.la \
- libgnunetcadettest.la \
- libgnunetcadet.la \
- $(top_builddir)/src/testbed/libgnunettestbed.la \
- $(top_builddir)/src/statistics/libgnunetstatistics.la
-
-dep_cadet_test_lib = \
- libgnunetcadet.la \
- libgnunetcadettest.la \
- $(top_builddir)/src/statistics/libgnunetstatistics.la
-
-
-gnunet_cadet_profiler_SOURCES = \
- gnunet-cadet-profiler.c
-gnunet_cadet_profiler_LDADD = $(ld_cadet_test_lib)
-
-test_cadet_single_SOURCES = \
- test_cadet_single.c
-test_cadet_single_LDADD = $(ld_cadet_test_lib)
-
-test_cadet_local_SOURCES = \
- test_cadet_local.c
-test_cadet_local_LDADD = $(ld_cadet_test_lib)
+#gnunet_cadet_profiler_SOURCES = \
+# gnunet-cadet-profiler.c
+#gnunet_cadet_profiler_LDADD = $(ld_cadet_test_lib)
test_cadet_local_mq_SOURCES = \
@@ -196,6 +125,26 @@ test_cadet_local_mq_LDADD = \
$(top_builddir)/src/testing/libgnunettesting.la \
$(top_builddir)/src/util/libgnunetutil.la
+
+libgnunetcadettest_la_SOURCES = \
+ cadet_test_lib.c cadet_test_lib.h
+libgnunetcadettest_la_LIBADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testbed/libgnunettestbed.la \
+ libgnunetcadetnew.la
+
+ld_cadet_test_lib = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ libgnunetcadetnew.la \
+ libgnunetcadettest.la \
+ $(top_builddir)/src/testbed/libgnunettestbed.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la
+dep_cadet_test_lib = \
+ libgnunetcadetnew.la \
+ libgnunetcadettest.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la
+
test_cadet_2_forward_SOURCES = \
test_cadet.c
test_cadet_2_forward_LDADD = $(ld_cadet_test_lib)
@@ -228,7 +177,6 @@ test_cadet_2_speed_reliable_backwards_SOURCES = \
test_cadet.c
test_cadet_2_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib)
-
test_cadet_5_forward_SOURCES = \
test_cadet.c
test_cadet_5_forward_LDADD = $(ld_cadet_test_lib)
@@ -262,92 +210,6 @@ test_cadet_5_speed_reliable_backwards_SOURCES = \
test_cadet_5_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib)
-# NEW TESTS
-libgnunetcadettestnew_la_SOURCES = \
- cadet_test_lib_new.c cadet_test_lib_new.h
-libgnunetcadettestnew_la_LIBADD = \
- $(top_builddir)/src/util/libgnunetutil.la \
- $(top_builddir)/src/testbed/libgnunettestbed.la \
- libgnunetcadetnew.la
-
-ld_cadet_test_lib_new = \
- $(top_builddir)/src/util/libgnunetutil.la \
- $(top_builddir)/src/testing/libgnunettesting.la \
- libgnunetcadetnew.la \
- libgnunetcadettestnew.la \
- $(top_builddir)/src/testbed/libgnunettestbed.la \
- $(top_builddir)/src/statistics/libgnunetstatistics.la
-dep_cadet_test_lib_new = \
- libgnunetcadetnew.la \
- libgnunetcadettestnew.la \
- $(top_builddir)/src/statistics/libgnunetstatistics.la
-
-test_cadet_2_forward_new_SOURCES = \
- test_cadet_new.c
-test_cadet_2_forward_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_2_signal_new_SOURCES = \
- test_cadet_new.c
-test_cadet_2_signal_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_2_keepalive_new_SOURCES = \
- test_cadet_new.c
-test_cadet_2_keepalive_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_2_speed_new_SOURCES = \
- test_cadet_new.c
-test_cadet_2_speed_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_2_speed_ack_new_SOURCES = \
- test_cadet_new.c
-test_cadet_2_speed_ack_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_2_speed_backwards_new_SOURCES = \
- test_cadet_new.c
-test_cadet_2_speed_backwards_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_2_speed_reliable_new_SOURCES = \
- test_cadet_new.c
-test_cadet_2_speed_reliable_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_2_speed_reliable_backwards_new_SOURCES = \
- test_cadet_new.c
-test_cadet_2_speed_reliable_backwards_new_LDADD = $(ld_cadet_test_lib_new)
-
-
-test_cadet_5_forward_new_SOURCES = \
- test_cadet_new.c
-test_cadet_5_forward_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_5_signal_new_SOURCES = \
- test_cadet_new.c
-test_cadet_5_signal_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_5_keepalive_new_SOURCES = \
- test_cadet_new.c
-test_cadet_5_keepalive_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_5_speed_new_SOURCES = \
- test_cadet_new.c
-test_cadet_5_speed_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_5_speed_ack_new_SOURCES = \
- test_cadet_new.c
-test_cadet_5_speed_ack_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_5_speed_backwards_new_SOURCES = \
- test_cadet_new.c
-test_cadet_5_speed_backwards_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_5_speed_reliable_new_SOURCES = \
- test_cadet_new.c
-test_cadet_5_speed_reliable_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_5_speed_reliable_backwards_new_SOURCES = \
- test_cadet_new.c
-test_cadet_5_speed_reliable_backwards_new_LDADD = $(ld_cadet_test_lib_new)
-
-
if ENABLE_TEST_RUN
AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
TESTS = \
diff --git a/src/cadet/cadet.conf.in b/src/cadet/cadet.conf.in
index 86ba2e535d..d50e168f09 100644
--- a/src/cadet/cadet.conf.in
+++ b/src/cadet/cadet.conf.in
@@ -3,7 +3,7 @@ FORCESTART = YES
AUTOSTART = @AUTOSTART@
@JAVAPORT@PORT = 2096
HOSTNAME = localhost
-BINARY = gnunet-service-cadet-new
+BINARY = gnunet-service-cadet
# PREFIX = valgrind --leak-check=yes
ACCEPT_FROM = 127.0.0.1;
ACCEPT_FROM6 = ::1;
diff --git a/src/cadet/cadet.h b/src/cadet/cadet.h
index 451d1f3543..99f9f26531 100644
--- a/src/cadet/cadet.h
+++ b/src/cadet/cadet.h
@@ -59,7 +59,7 @@ extern "C"
#include "gnunet_core_service.h"
#include "gnunet_cadet_service.h"
#include "gnunet_protocols.h"
-#include <gnunet_cadet_service.h>
+#include "gnunet_cadet_service.h"
/******************************************************************************/
/************************** CONSTANTS ******************************/
diff --git a/src/cadet/cadet_path.c b/src/cadet/cadet_path.c
deleted file mode 100644
index 79a498805b..0000000000
--- a/src/cadet/cadet_path.c
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2001 - 2013 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, 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"
-
-#define LOG(level, ...) GNUNET_log_from (level,"cadet-pth",__VA_ARGS__)
-
-
-/**
- * @brief Destroy a path after some time has past.
- * Removes the path from the peer (must not be used for direct paths).
- *
- * @param cls Closure (path to destroy).
- */
-static void
-path_destroy_delayed (void *cls)
-{
- struct CadetPeerPath *path = cls;
- struct CadetPeer *peer;
-
- path->path_delete = NULL;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Destroy delayed %p (%u)\n",
- path,
- path->length);
- GNUNET_assert (2 < path->length);
- peer = GCP_get_short (path->peers[path->length - 1],
- GNUNET_NO);
- GNUNET_assert (NULL != peer);
- GCP_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));
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "New path %p (%u)\n", p, p->length);
- 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);
- GNUNET_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.
- *
- * Never invalidates a two-hop (direct) path, only a core handler can do that.
- *
- * Rationale: 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. The path must remain "known and marked as invalid" for a while.
- *
- * @param p Path to invalidate.
- */
-void
-path_invalidate (struct CadetPeerPath *p)
-{
- if (NULL != p->path_delete)
- return;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Invalidating path %p (%u)\n",
- p,
- p->length);
- p->path_delete
- = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
- &path_destroy_delayed, p);
-}
-
-
-/**
- * Builds a path from a PeerIdentity array.
- *
- * @param peers PeerIdentity array.
- * @param size Size of the @c peers array.
- * @param myid ID of local peer, to find @c own_pos.
- * @param own_pos Output parameter: own position in the path.
- *
- * @return Fixed and shortened path.
- */
-struct CadetPeerPath *
-path_build_from_peer_ids (struct GNUNET_PeerIdentity *peers,
- unsigned int size,
- GNUNET_PEER_Id myid,
- 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;
-}
-
-
-/**
- * Test if two paths are equivalent (equal or revese of each other).
- *
- * @param p1 First path
- * @param p2 Second path
- *
- * @return #GNUNET_YES if both paths are equivalent
- * #GNUNET_NO otherwise
- */
-int
-path_equivalent (const struct CadetPeerPath *p1,
- const struct CadetPeerPath *p2)
-{
- unsigned int i;
- unsigned int l;
- unsigned int half;
-
- if (NULL == p1 || NULL == p2)
- return GNUNET_NO;
-
- if (p1->length != p2->length)
- return GNUNET_NO;
-
- l = p1->length;
- if (0 == memcmp (p1->peers, p2->peers, sizeof (p1->peers[0]) * l))
- return GNUNET_YES;
-
- half = l / 2;
- l = l - 1;
- for (i = 0; i <= half; i++)
- if (p1->peers[i] != p2->peers[l - i])
- return GNUNET_NO;
-
- return GNUNET_YES;
-}
-
-
-/**
- * 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 (NULL == 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;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "destroying path %p (%u)\n",
- p,
- p->length);
- GNUNET_PEER_decrement_rcs (p->peers, p->length);
- GNUNET_free_non_null (p->peers);
- if (NULL != p->path_delete)
- GNUNET_SCHEDULER_cancel (p->path_delete);
- GNUNET_free (p);
- return GNUNET_OK;
-}
-
-
-/**
- * Compare two paths.
- *
- * @param p1 First path.
- * @param p2 Second path.
- *
- * @return > 0 if p1 is longer, or the first differing PEER_Id is higher on p1.
- * < 0 if p2 is longer, or the first differing PEER_Id is higher on p2.
- * 0 if they are identical.
- */
-int
-path_cmp (const struct CadetPeerPath *p1,
- const struct CadetPeerPath *p2)
-{
- if (p1->length > p2->length)
- return 1;
-
- if (p1->length < p2->length)
- return -1;
-
- return memcmp (p1->peers,
- p2->peers,
- sizeof (GNUNET_PEER_Id) * p1->length);
-}
-
-
-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 old;
-}
-
-
-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
deleted file mode 100644
index bb68eec42e..0000000000
--- a/src/cadet/cadet_path.h
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2001 - 2013 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/cadet_path.h
- * @brief Path handling functions
- * @author Bartlomiej Polot
- */
-
-#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.
- */
- struct GNUNET_SCHEDULER_Task * 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 two paths are equivalent (equal or revese of each other).
- *
- * @param p1 First path
- * @param p2 Second path
- *
- * @return GNUNET_YES if both paths are equivalent
- * GNUNET_NO otherwise
- */
-int
-path_equivalent (const struct CadetPeerPath *p1,
- const struct CadetPeerPath *p2);
-
-/**
- * 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);
-
-/**
- * Compare two paths.
- *
- * @param p1 First path.
- * @param p2 Second path.
- *
- * @return > 0 if p1 is longer, or the first differing PEER_Id is higher on p1.
- * < 0 if p2 is longer, or the first differing PEER_Id is higher on p2.
- * 0 if they are identical.
- */
-int
-path_cmp (const struct CadetPeerPath *p1, const struct CadetPeerPath *p2);
-
-/**
- * Builds a path from a PeerIdentity array.
- *
- * @param peers PeerIdentity array.
- * @param size Size of the @c peers array.
- * @param myid ID of local peer, to find @c own_pos.
- * @param own_pos Output parameter: own position in the path.
- *
- * @return Fixed and shortened path.
- */
-struct CadetPeerPath *
-path_build_from_peer_ids (struct GNUNET_PeerIdentity *peers,
- unsigned int size,
- GNUNET_PEER_Id myid,
- unsigned int *own_pos);
-
-/**
- * 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
index d2426addbd..560c186cd5 100644
--- a/src/cadet/cadet_protocol.h
+++ b/src/cadet/cadet_protocol.h
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet.
- Copyright (C) 2001 - 2011 GNUnet e.V.
+ Copyright (C) 2007 - 2017 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
@@ -19,8 +19,10 @@
*/
/**
- * @author Bartlomiej Polot
* @file cadet/cadet_protocol.h
+ * @brief P2P messages used by CADET
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
*/
#ifndef CADET_PROTOCOL_H_
@@ -298,17 +300,10 @@ struct GNUNET_CADET_TunnelEncryptedMessage
*/
struct GNUNET_MessageHeader header;
-#if NEW_CADET
/**
* Reserved, for alignment.
*/
uint32_t reserved GNUNET_PACKED;
-#else
- /**
- * Maximum packet ID authorized.
- */
- struct CadetEncryptedMessageIdentifier cemi;
-#endif
/**
* ID of the connection.
@@ -322,89 +317,18 @@ struct GNUNET_CADET_TunnelEncryptedMessage
*/
struct GNUNET_ShortHashCode hmac;
- #if NEW_CADET
/**
* Axolotl-header that specifies which keys to use in which ratchet
* to decrypt the body that follows.
*/
struct GNUNET_CADET_AxHeader ax_header;
-#else
- /**
- * Number of messages sent with the current ratchet key.
- */
- uint32_t Ns GNUNET_PACKED;
-
- /**
- * Number of messages sent with the previous ratchet key.
- */
- uint32_t PNs GNUNET_PACKED;
/**
- * Current ratchet key.
- */
- struct GNUNET_CRYPTO_EcdhePublicKey DHRs;
-#endif
- /**
* Encrypted content follows.
*/
};
-#ifndef NEW_CADET
-
-/**
- * Message to query a peer about its Flow Control status regarding a tunnel.
- *
- * It is NOT yet clear if we need this.
- */
-struct GNUNET_CADET_ConnectionHopByHopPollMessage
-{
- /**
- * Type: #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * Last packet sent.
- */
- struct CadetEncryptedMessageIdentifier cemi;
-
- /**
- * ID of the connection.
- */
- struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
-
-};
-
-
-/**
- * Message to acknowledge cadet encrypted traffic, used for
- * flow-control on a hop-by-hop basis on the connection-level. Note
- * that we do use the @e cemi from the tunnel layer as the connection
- * layer's header is included/shared with the tunnel layer messages,
- * and we only do flow control for the payload.
- */
-struct GNUNET_CADET_ConnectionEncryptedAckMessage
-{
- /**
- * Type: #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * Maximum packet ID authorized.
- */
- struct CadetEncryptedMessageIdentifier cemi_max;
-
- /**
- * ID of the connection.
- */
- struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
-};
-
-#endif
-
-
/******************************************************************************/
/******************************* CHANNEL ***********************************/
/******************************************************************************/
@@ -450,83 +374,19 @@ struct GNUNET_CADET_ChannelManageMessage
*/
struct GNUNET_MessageHeader header;
-#ifdef NEW_CADET
/**
* For alignment.
*/
uint32_t reserved GNUNET_PACKED;
-#endif
-
- /**
- * ID of the channel
- */
- struct GNUNET_CADET_ChannelTunnelNumber ctn;
-};
-
-
-#ifndef NEW_CADET
-
-/**
- * Message for cadet data traffic.
- */
-struct GNUNET_CADET_ChannelAppDataMessage
-{
- /**
- * Type: #GNUNET_MESSAGE_TYPE_CADET_UNICAST,
- * #GNUNET_MESSAGE_TYPE_CADET_TO_ORIGIN
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * Unique ID of the payload message
- */
- /* NEW: struct ChannelMessageIdentifier */
- uint32_t mid GNUNET_PACKED;
/**
* ID of the channel
*/
struct GNUNET_CADET_ChannelTunnelNumber ctn;
-
- /**
- * Payload follows
- */
};
/**
- * Message to acknowledge end-to-end data.
- */
-struct GNUNET_CADET_ChannelDataAckMessage
-{
- /**
- * Type: #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * ID of the channel
- */
- struct GNUNET_CADET_ChannelTunnelNumber ctn;
-
- /**
- * Bitfield of already-received messages past @e mid.
- * pid + 1 @ LSB
- * pid + 64 @ MSB
- */
- uint64_t futures GNUNET_PACKED;
-
- /**
- * Last message ID received.
- */
- /* NEW: struct ChannelMessageIdentifier */
- uint32_t mid GNUNET_PACKED;
-};
-
-#else
-
-
-/**
* Number used to uniquely identify messages in a CADET Channel.
*/
struct ChannelMessageIdentifier
@@ -595,8 +455,6 @@ struct GNUNET_CADET_ChannelDataAckMessage
};
-#endif
-
GNUNET_NETWORK_STRUCT_END
#if 0 /* keep Emacsens' auto-indent happy */
diff --git a/src/cadet/cadet_test_lib.c b/src/cadet/cadet_test_lib.c
index 9a70dad493..c3a1540f42 100644
--- a/src/cadet/cadet_test_lib.c
+++ b/src/cadet/cadet_test_lib.c
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet.
- Copyright (C) 2012 GNUnet e.V.
+ Copyright (C) 2012, 2017 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
@@ -24,9 +24,10 @@
*/
#include "platform.h"
#include "gnunet_util_lib.h"
-#include "cadet_test_lib.h"
+#include "cadet_test_lib_new.h"
#include "gnunet_cadet_service.h"
+
/**
* Test context for a CADET Test.
*/
@@ -40,7 +41,7 @@ struct GNUNET_CADET_TEST_Context
/**
* Array of handles to the CADET for each peer.
*/
- struct GNUNET_CADET_Handle **cadetes;
+ struct GNUNET_CADET_Handle **cadets;
/**
* Operation associated with the connection to the CADET.
@@ -48,6 +49,11 @@ struct GNUNET_CADET_TEST_Context
struct GNUNET_TESTBED_Operation **ops;
/**
+ * Number of peers running, size of the arrays above.
+ */
+ unsigned int num_peers;
+
+ /**
* Main function of the test to run once all CADETs are available.
*/
GNUNET_CADET_TEST_AppMain app_main;
@@ -58,30 +64,35 @@ struct GNUNET_CADET_TEST_Context
void *app_main_cls;
/**
- * Number of peers running, size of the arrays above.
+ * Handler for incoming tunnels.
*/
- unsigned int num_peers;
+ GNUNET_CADET_ConnectEventHandler connects;
/**
- * Handler for incoming tunnels.
+ * Function called when the transmit window size changes.
*/
- GNUNET_CADET_InboundChannelNotificationHandler *new_channel;
+ GNUNET_CADET_WindowSizeEventHandler window_changes;
/**
* Cleaner for destroyed incoming tunnels.
*/
- GNUNET_CADET_ChannelEndHandler *cleaner;
+ GNUNET_CADET_DisconnectEventHandler disconnects;
/**
* Message handlers.
*/
- struct GNUNET_CADET_MessageHandler* handlers;
+ struct GNUNET_MQ_MessageHandler *handlers;
/**
* Application ports.
*/
const struct GNUNET_HashCode **ports;
+ /**
+ * Number of ports in #ports.
+ */
+ unsigned int port_count;
+
};
@@ -94,6 +105,11 @@ struct GNUNET_CADET_TEST_AdapterContext
* Peer number for the particular peer.
*/
unsigned int peer;
+
+ /**
+ * Port handlers for open ports.
+ */
+ struct GNUNET_CADET_Port **ports;
/**
* General context.
@@ -114,26 +130,28 @@ struct GNUNET_CADET_TEST_AdapterContext
*/
static void *
cadet_connect_adapter (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
+ 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;
+ unsigned int i;
- h = GNUNET_CADET_connect (cfg,
- (void *) (long) actx->peer,
- ctx->cleaner,
- ctx->handlers);
+ h = GNUNET_CADET_connecT (cfg);
if (NULL == ctx->ports)
return h;
- for (int i = 0; NULL != ctx->ports[i]; i++)
+ actx->ports = GNUNET_new_array (ctx->port_count, struct GNUNET_CADET_Port *);
+ for (i = 0; i < ctx->port_count; i++)
{
- (void ) GNUNET_CADET_open_port (h, ctx->ports[i],
- ctx->new_channel,
- (void *) (long) actx->peer);
+ actx->ports[i] = GNUNET_CADET_open_porT (h,
+ ctx->ports[i],
+ ctx->connects,
+ (void *) (long) actx->peer,
+ ctx->window_changes,
+ ctx->disconnects,
+ ctx->handlers);
}
-
return h;
}
@@ -152,6 +170,15 @@ cadet_disconnect_adapter (void *cls,
struct GNUNET_CADET_Handle *cadet = op_result;
struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
+ if (NULL != actx->ports)
+ {
+ for (int i = 0; i < actx->ctx->port_count; i++)
+ {
+ GNUNET_CADET_close_port (actx->ports[i]);
+ actx->ports[i] = NULL;
+ }
+ GNUNET_free (actx->ports);
+ }
GNUNET_free (actx);
GNUNET_CADET_disconnect (cadet);
}
@@ -186,18 +213,18 @@ cadet_connect_cb (void *cls,
for (i = 0; i < ctx->num_peers; i++)
if (op == ctx->ops[i])
{
- ctx->cadetes[i] = ca_result;
+ ctx->cadets[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])
+ if (NULL == ctx->cadets[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);
+ ctx->cadets);
}
@@ -213,7 +240,7 @@ GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx)
ctx->ops[i] = NULL;
}
GNUNET_free (ctx->ops);
- GNUNET_free (ctx->cadetes);
+ GNUNET_free (ctx->cadets);
GNUNET_free (ctx);
GNUNET_SCHEDULER_shutdown ();
}
@@ -243,12 +270,23 @@ cadet_test_run (void *cls,
struct GNUNET_CADET_TEST_Context *ctx = cls;
unsigned int i;
+ if (0 != links_failed)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Some links failed (%u), ending\n",
+ links_failed);
+ exit (2);
+ }
+
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);
}
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Testbed up, %u peers and %u links\n",
+ num_peers, links_succeeded);
ctx->peers = peers;
for (i = 0; i < num_peers; i++)
{
@@ -270,31 +308,52 @@ cadet_test_run (void *cls,
}
+/**
+ * Run a test using the given name, configuration file and number of peers.
+ * All cadet callbacks will receive the peer number (long) as the closure.
+ *
+ * @param testname Name of the test (for logging).
+ * @param cfgfile 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 @a tmain.
+ * @param connects Handler for incoming channels.
+ * @param window_changes Handler for the window size change notification.
+ * @param disconnects Cleaner for destroyed incoming channels.
+ * @param handlers Message handlers.
+ * @param ports Ports the peers offer, NULL-terminated.
+ */
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 struct GNUNET_HashCode **ports)
+GNUNET_CADET_TEST_ruN (const char *testname,
+ const char *cfgfile,
+ unsigned int num_peers,
+ GNUNET_CADET_TEST_AppMain tmain,
+ void *tmain_cls,
+ GNUNET_CADET_ConnectEventHandler connects,
+ GNUNET_CADET_WindowSizeEventHandler window_changes,
+ GNUNET_CADET_DisconnectEventHandler disconnects,
+ struct GNUNET_MQ_MessageHandler *handlers,
+ const struct GNUNET_HashCode **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->ops = GNUNET_new_array (num_peers, struct GNUNET_TESTBED_Operation *);
+ ctx->cadets = GNUNET_new_array (num_peers, 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->connects = connects;
+ ctx->window_changes = window_changes;
+ ctx->disconnects = disconnects;
+ ctx->handlers = GNUNET_MQ_copy_handlers (handlers);
ctx->ports = ports;
+ ctx->port_count = 0;
+ while (NULL != ctx->ports[ctx->port_count])
+ ctx->port_count++;
+
GNUNET_TESTBED_test_run (testname,
- cfgname,
+ cfgfile,
num_peers,
0LL, NULL, NULL,
&cadet_test_run, ctx);
diff --git a/src/cadet/cadet_test_lib.h b/src/cadet/cadet_test_lib.h
index 464977d42d..4b3a6b18dd 100644
--- a/src/cadet/cadet_test_lib.h
+++ b/src/cadet/cadet_test_lib.h
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet.
- Copyright (C) 2012 GNUnet e.V.
+ Copyright (C) 2012,2017 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
@@ -49,41 +49,41 @@ struct GNUNET_CADET_TEST_Context;
* @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.
+ * @param cadets 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);
+ struct GNUNET_CADET_Handle **cadets);
/**
- * Run a test using the given name, configuration file and number of
- * peers.
- * All cadet callbacks will receive the peer number as the closure.
+ * Run a test using the given name, configuration file and number of peers.
+ * All cadet callbacks will receive the peer number (long) as the closure.
*
* @param testname Name of the test (for logging).
- * @param cfgname Name of the configuration file.
+ * @param cfgfile 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 tmain_cls Closure for @a tmain.
+ * @param connects Handler for incoming channels.
+ * @param window_changes Handler for the window size change notification.
+ * @param disconnects Cleaner for destroyed incoming channels.
* @param handlers Message handlers.
* @param ports Ports the peers offer, NULL-terminated.
*/
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 struct GNUNET_HashCode **ports);
-
+GNUNET_CADET_TEST_ruN (const char *testname,
+ const char *cfgfile,
+ unsigned int num_peers,
+ GNUNET_CADET_TEST_AppMain tmain,
+ void *tmain_cls,
+ GNUNET_CADET_ConnectEventHandler connects,
+ GNUNET_CADET_WindowSizeEventHandler window_changes,
+ GNUNET_CADET_DisconnectEventHandler disconnects,
+ struct GNUNET_MQ_MessageHandler *handlers,
+ const struct GNUNET_HashCode **ports);
/**
* Clean up the testbed.
diff --git a/src/cadet/cadet_test_lib_new.c b/src/cadet/cadet_test_lib_new.c
deleted file mode 100644
index c3a1540f42..0000000000
--- a/src/cadet/cadet_test_lib_new.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2012, 2017 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, 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_new.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 **cadets;
-
- /**
- * Operation associated with the connection to the CADET.
- */
- struct GNUNET_TESTBED_Operation **ops;
-
- /**
- * Number of peers running, size of the arrays above.
- */
- unsigned int num_peers;
-
- /**
- * 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;
-
- /**
- * Handler for incoming tunnels.
- */
- GNUNET_CADET_ConnectEventHandler connects;
-
- /**
- * Function called when the transmit window size changes.
- */
- GNUNET_CADET_WindowSizeEventHandler window_changes;
-
- /**
- * Cleaner for destroyed incoming tunnels.
- */
- GNUNET_CADET_DisconnectEventHandler disconnects;
-
- /**
- * Message handlers.
- */
- struct GNUNET_MQ_MessageHandler *handlers;
-
- /**
- * Application ports.
- */
- const struct GNUNET_HashCode **ports;
-
- /**
- * Number of ports in #ports.
- */
- unsigned int port_count;
-
-};
-
-
-/**
- * Context for a cadet adapter callback.
- */
-struct GNUNET_CADET_TEST_AdapterContext
-{
- /**
- * Peer number for the particular peer.
- */
- unsigned int peer;
-
- /**
- * Port handlers for open ports.
- */
- struct GNUNET_CADET_Port **ports;
-
- /**
- * 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;
- unsigned int i;
-
- h = GNUNET_CADET_connecT (cfg);
- if (NULL == ctx->ports)
- return h;
-
- actx->ports = GNUNET_new_array (ctx->port_count, struct GNUNET_CADET_Port *);
- for (i = 0; i < ctx->port_count; i++)
- {
- actx->ports[i] = GNUNET_CADET_open_porT (h,
- ctx->ports[i],
- ctx->connects,
- (void *) (long) actx->peer,
- ctx->window_changes,
- ctx->disconnects,
- ctx->handlers);
- }
- 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;
-
- if (NULL != actx->ports)
- {
- for (int i = 0; i < actx->ctx->port_count; i++)
- {
- GNUNET_CADET_close_port (actx->ports[i]);
- actx->ports[i] = NULL;
- }
- GNUNET_free (actx->ports);
- }
- 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->cadets[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->cadets[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->cadets);
-}
-
-
-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->cadets);
- 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 (0 != links_failed)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Some links failed (%u), ending\n",
- links_failed);
- exit (2);
- }
-
- 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);
- }
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Testbed up, %u peers and %u links\n",
- num_peers, links_succeeded);
- 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]);
- }
-}
-
-
-/**
- * Run a test using the given name, configuration file and number of peers.
- * All cadet callbacks will receive the peer number (long) as the closure.
- *
- * @param testname Name of the test (for logging).
- * @param cfgfile 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 @a tmain.
- * @param connects Handler for incoming channels.
- * @param window_changes Handler for the window size change notification.
- * @param disconnects Cleaner for destroyed incoming channels.
- * @param handlers Message handlers.
- * @param ports Ports the peers offer, NULL-terminated.
- */
-void
-GNUNET_CADET_TEST_ruN (const char *testname,
- const char *cfgfile,
- unsigned int num_peers,
- GNUNET_CADET_TEST_AppMain tmain,
- void *tmain_cls,
- GNUNET_CADET_ConnectEventHandler connects,
- GNUNET_CADET_WindowSizeEventHandler window_changes,
- GNUNET_CADET_DisconnectEventHandler disconnects,
- struct GNUNET_MQ_MessageHandler *handlers,
- const struct GNUNET_HashCode **ports)
-{
- struct GNUNET_CADET_TEST_Context *ctx;
-
- ctx = GNUNET_new (struct GNUNET_CADET_TEST_Context);
- ctx->num_peers = num_peers;
- ctx->ops = GNUNET_new_array (num_peers, struct GNUNET_TESTBED_Operation *);
- ctx->cadets = GNUNET_new_array (num_peers, struct GNUNET_CADET_Handle *);
- ctx->app_main = tmain;
- ctx->app_main_cls = tmain_cls;
- ctx->connects = connects;
- ctx->window_changes = window_changes;
- ctx->disconnects = disconnects;
- ctx->handlers = GNUNET_MQ_copy_handlers (handlers);
- ctx->ports = ports;
- ctx->port_count = 0;
- while (NULL != ctx->ports[ctx->port_count])
- ctx->port_count++;
-
- GNUNET_TESTBED_test_run (testname,
- cfgfile,
- num_peers,
- 0LL, NULL, NULL,
- &cadet_test_run, ctx);
-}
-
-/* end of cadet_test_lib.c */
diff --git a/src/cadet/cadet_test_lib_new.h b/src/cadet/cadet_test_lib_new.h
deleted file mode 100644
index 4b3a6b18dd..0000000000
--- a/src/cadet/cadet_test_lib_new.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2012,2017 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, 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 cadets 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 **cadets);
-
-
-/**
- * Run a test using the given name, configuration file and number of peers.
- * All cadet callbacks will receive the peer number (long) as the closure.
- *
- * @param testname Name of the test (for logging).
- * @param cfgfile 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 @a tmain.
- * @param connects Handler for incoming channels.
- * @param window_changes Handler for the window size change notification.
- * @param disconnects Cleaner for destroyed incoming channels.
- * @param handlers Message handlers.
- * @param ports Ports the peers offer, NULL-terminated.
- */
-void
-GNUNET_CADET_TEST_ruN (const char *testname,
- const char *cfgfile,
- unsigned int num_peers,
- GNUNET_CADET_TEST_AppMain tmain,
- void *tmain_cls,
- GNUNET_CADET_ConnectEventHandler connects,
- GNUNET_CADET_WindowSizeEventHandler window_changes,
- GNUNET_CADET_DisconnectEventHandler disconnects,
- struct GNUNET_MQ_MessageHandler *handlers,
- const struct GNUNET_HashCode **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/gnunet-service-cadet-new.c b/src/cadet/gnunet-service-cadet-new.c
deleted file mode 100644
index 93f53de4c8..0000000000
--- a/src/cadet/gnunet-service-cadet-new.c
+++ /dev/null
@@ -1,1496 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2001-2013, 2017 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new.c
- * @brief GNUnet CADET service with encryption
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * Dictionary:
- * - peer: other cadet instance. If there is direct connection it's a neighbor.
- * - path: series of directly connected peer from one peer to another.
- * - connection: path which is being used in a tunnel.
- * - tunnel: encrypted connection to a peer, neighbor or not.
- * - channel: logical link between two clients, on the same or different peers.
- * have properties like reliability.
- */
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "cadet.h"
-#include "gnunet_statistics_service.h"
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_channel.h"
-#include "gnunet-service-cadet-new_connection.h"
-#include "gnunet-service-cadet-new_core.h"
-#include "gnunet-service-cadet-new_dht.h"
-#include "gnunet-service-cadet-new_hello.h"
-#include "gnunet-service-cadet-new_tunnels.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_paths.h"
-
-#define LOG(level, ...) GNUNET_log (level,__VA_ARGS__)
-
-
-/**
- * Struct containing information about a client of the service
- */
-struct CadetClient
-{
- /**
- * Linked list next
- */
- struct CadetClient *next;
-
- /**
- * Linked list prev
- */
- struct CadetClient *prev;
-
- /**
- * Tunnels that belong to this client, indexed by local id,
- * value is a `struct CadetChannel`.
- */
- struct GNUNET_CONTAINER_MultiHashMap32 *channels;
-
- /**
- * Handle to communicate with the client
- */
- struct GNUNET_MQ_Handle *mq;
-
- /**
- * Client handle.
- */
- struct GNUNET_SERVICE_Client *client;
-
- /**
- * Ports that this client has declared interest in.
- * Indexed by port, contains *Client.
- */
- struct GNUNET_CONTAINER_MultiHashMap *ports;
-
- /**
- * Channel ID to use for the next incoming channel for this client.
- * Wraps around (in theory).
- */
- struct GNUNET_CADET_ClientChannelNumber next_ccn;
-
- /**
- * ID of the client, mainly for debug messages. Purely internal to this file.
- */
- unsigned int id;
-};
-
-/******************************************************************************/
-/*********************** GLOBAL VARIABLES ****************************/
-/******************************************************************************/
-
-/****************************** Global variables ******************************/
-
-/**
- * Handle to our configuration.
- */
-const struct GNUNET_CONFIGURATION_Handle *cfg;
-
-/**
- * Handle to the statistics service.
- */
-struct GNUNET_STATISTICS_Handle *stats;
-
-/**
- * Handle to communicate with ATS.
- */
-struct GNUNET_ATS_ConnectivityHandle *ats_ch;
-
-/**
- * Local peer own ID.
- */
-struct GNUNET_PeerIdentity my_full_id;
-
-/**
- * Own private key.
- */
-struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
-
-/**
- * Signal that shutdown is happening: prevent recovery measures.
- */
-int shutting_down;
-
-/**
- * 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.
- */
-static unsigned int next_client_id;
-
-/**
- * All ports clients of this peer have opened.
- */
-struct GNUNET_CONTAINER_MultiHashMap *open_ports;
-
-/**
- * Map from ports to channels where the ports were closed at the
- * time we got the inbound connection.
- * Indexed by port, contains `struct CadetChannel`.
- */
-struct GNUNET_CONTAINER_MultiHashMap *loose_channels;
-
-/**
- * Map from PIDs to `struct CadetPeer` entries.
- */
-struct GNUNET_CONTAINER_MultiPeerMap *peers;
-
-/**
- * Map from `struct GNUNET_CADET_ConnectionTunnelIdentifier`
- * hash codes to `struct CadetConnection` objects.
- */
-struct GNUNET_CONTAINER_MultiShortmap *connections;
-
-/**
- * How many messages are needed to trigger an AXOLOTL ratchet advance.
- */
-unsigned long long ratchet_messages;
-
-/**
- * How long until we trigger a ratched advance due to time.
- */
-struct GNUNET_TIME_Relative ratchet_time;
-
-/**
- * How frequently do we send KEEPALIVE messages on idle connections?
- */
-struct GNUNET_TIME_Relative keepalive_period;
-
-/**
- * Set to non-zero values to create random drops to test retransmissions.
- */
-unsigned long long drop_percent;
-
-
-/**
- * Send a message to a client.
- *
- * @param c client to get the message
- * @param env envelope with the message
- */
-void
-GSC_send_to_client (struct CadetClient *c,
- struct GNUNET_MQ_Envelope *env)
-{
- GNUNET_MQ_send (c->mq,
- env);
-}
-
-
-/**
- * Return identifier for a client as a string.
- *
- * @param c client to identify
- * @return string for debugging
- */
-const char *
-GSC_2s (struct CadetClient *c)
-{
- static char buf[32];
-
- GNUNET_snprintf (buf,
- sizeof (buf),
- "Client(%u)",
- c->id);
- return buf;
-}
-
-
-/**
- * Lookup channel of client @a c by @a ccn.
- *
- * @param c client to look in
- * @param ccn channel ID to look up
- * @return NULL if no such channel exists
- */
-static struct CadetChannel *
-lookup_channel (struct CadetClient *c,
- struct GNUNET_CADET_ClientChannelNumber ccn)
-{
- return GNUNET_CONTAINER_multihashmap32_get (c->channels,
- ntohl (ccn.channel_of_client));
-}
-
-
-/**
- * Obtain the next LID to use for incoming connections to
- * the given client.
- *
- * @param c client handle
- */
-static struct GNUNET_CADET_ClientChannelNumber
-client_get_next_ccn (struct CadetClient *c)
-{
- struct GNUNET_CADET_ClientChannelNumber ccn = c->next_ccn;
-
- /* increment until we have a free one... */
- while (NULL !=
- lookup_channel (c,
- ccn))
- {
- ccn.channel_of_client
- = htonl (1 + (ntohl (ccn.channel_of_client)));
- if (ntohl (ccn.channel_of_client) >=
- GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
- ccn.channel_of_client = htonl (0);
- }
- c->next_ccn.channel_of_client
- = htonl (1 + (ntohl (ccn.channel_of_client)));
- return ccn;
-}
-
-
-/**
- * Bind incoming channel to this client, and notify client about
- * incoming connection. Caller is responsible for notifying the other
- * peer about our acceptance of the channel.
- *
- * @param c client to bind to
- * @param ch channel to be bound
- * @param dest peer that establishes the connection
- * @param port port number
- * @param options options
- * @return local channel number assigned to the new client
- */
-struct GNUNET_CADET_ClientChannelNumber
-GSC_bind (struct CadetClient *c,
- struct CadetChannel *ch,
- struct CadetPeer *dest,
- const struct GNUNET_HashCode *port,
- uint32_t options)
-{
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_CADET_LocalChannelCreateMessage *cm;
- struct GNUNET_CADET_ClientChannelNumber ccn;
-
- ccn = client_get_next_ccn (c);
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap32_put (c->channels,
- ntohl (ccn.channel_of_client),
- ch,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Accepting incoming %s from %s on open port %s (%u), assigning ccn %X\n",
- GCCH_2s (ch),
- GCP_2s (dest),
- GNUNET_h2s (port),
- (uint32_t) ntohl (options),
- (uint32_t) ntohl (ccn.channel_of_client));
- /* notify local client about incoming connection! */
- env = GNUNET_MQ_msg (cm,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
- cm->ccn = ccn;
- cm->port = *port;
- cm->opt = htonl (options);
- cm->peer = *GCP_get_id (dest);
- GSC_send_to_client (c,
- env);
- return ccn;
-}
-
-
-/**
- * Callback invoked on all peers to destroy all tunnels
- * that may still exist.
- *
- * @param cls NULL
- * @param pid identify of a peer
- * @param value a `struct CadetPeer` that may still have a tunnel
- * @return #GNUNET_OK (iterate over all entries)
- */
-static int
-destroy_tunnels_now (void *cls,
- const struct GNUNET_PeerIdentity *pid,
- void *value)
-{
- struct CadetPeer *cp = value;
- struct CadetTunnel *t = GCP_get_tunnel (cp,
- GNUNET_NO);
-
- if (NULL != t)
- GCT_destroy_tunnel_now (t);
- return GNUNET_OK;
-}
-
-
-/**
- * Callback invoked on all peers to destroy all tunnels
- * that may still exist.
- *
- * @param cls NULL
- * @param pid identify of a peer
- * @param value a `struct CadetPeer` that may still have a tunnel
- * @return #GNUNET_OK (iterate over all entries)
- */
-static int
-destroy_paths_now (void *cls,
- const struct GNUNET_PeerIdentity *pid,
- void *value)
-{
- struct CadetPeer *cp = value;
-
- GCP_drop_owned_paths (cp);
- return GNUNET_OK;
-}
-
-
-/**
- * Shutdown everything once the clients have disconnected.
- */
-static void
-shutdown_rest ()
-{
- if (NULL != stats)
- {
- GNUNET_STATISTICS_destroy (stats,
- GNUNET_NO);
- stats = NULL;
- }
- if (NULL != open_ports)
- {
- GNUNET_CONTAINER_multihashmap_destroy (open_ports);
- open_ports = NULL;
- }
- if (NULL != loose_channels)
- {
- GNUNET_CONTAINER_multihashmap_destroy (loose_channels);
- loose_channels = NULL;
- }
- /* Destroy tunnels. Note that all channels must be destroyed first! */
- GCP_iterate_all (&destroy_tunnels_now,
- NULL);
- /* All tunnels, channels, connections and CORE must be down before this point. */
- GCP_iterate_all (&destroy_paths_now,
- NULL);
- /* All paths, tunnels, channels, connections and CORE must be down before this point. */
- GCP_destroy_all_peers ();
- if (NULL != peers)
- {
- GNUNET_CONTAINER_multipeermap_destroy (peers);
- peers = NULL;
- }
- if (NULL != connections)
- {
- GNUNET_CONTAINER_multishortmap_destroy (connections);
- connections = NULL;
- }
- if (NULL != ats_ch)
- {
- GNUNET_ATS_connectivity_done (ats_ch);
- ats_ch = NULL;
- }
- GCD_shutdown ();
- GCH_shutdown ();
- GNUNET_free_non_null (my_private_key);
- my_private_key = NULL;
-}
-
-
-/**
- * Task run during shutdown.
- *
- * @param cls unused
- */
-static void
-shutdown_task (void *cls)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Shutting down\n");
- shutting_down = GNUNET_YES;
- GCO_shutdown ();
- if (NULL == clients_head)
- shutdown_rest ();
-}
-
-
-/**
- * We had a remote connection @a value to port @a port before
- * client @a cls opened port @a port. Bind them now.
- *
- * @param cls the `struct CadetClient`
- * @param port the port
- * @param value the `struct CadetChannel`
- * @return #GNUNET_YES (iterate over all such channels)
- */
-static int
-bind_loose_channel (void *cls,
- const struct GNUNET_HashCode *port,
- void *value)
-{
- struct CadetClient *c = cls;
- struct CadetChannel *ch = value;
-
- GCCH_bind (ch,
- c);
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_remove (loose_channels,
- port,
- value));
- return GNUNET_YES;
-}
-
-
-/**
- * Handle port open request. Creates a mapping from the
- * port to the respective client and checks whether we have
- * loose channels trying to bind to the port. If so, those
- * are bound.
- *
- * @param cls Identification of the client.
- * @param pmsg The actual message.
- */
-static void
-handle_port_open (void *cls,
- const struct GNUNET_CADET_PortMessage *pmsg)
-{
- struct CadetClient *c = cls;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Open port %s requested by %s\n",
- GNUNET_h2s (&pmsg->port),
- GSC_2s (c));
- if (NULL == c->ports)
- c->ports = GNUNET_CONTAINER_multihashmap_create (4,
- GNUNET_NO);
- if (GNUNET_OK !=
- GNUNET_CONTAINER_multihashmap_put (c->ports,
- &pmsg->port,
- c,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
- {
- GNUNET_break (0);
- GNUNET_SERVICE_client_drop (c->client);
- return;
- }
- (void) GNUNET_CONTAINER_multihashmap_put (open_ports,
- &pmsg->port,
- c,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
- GNUNET_CONTAINER_multihashmap_get_multiple (loose_channels,
- &pmsg->port,
- &bind_loose_channel,
- c);
- GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Handler for port close requests. Marks this port as closed
- * (unless of course we have another client with the same port
- * open). Note that existing channels accepted on the port are
- * not affected.
- *
- * @param cls Identification of the client.
- * @param pmsg The actual message.
- */
-static void
-handle_port_close (void *cls,
- const struct GNUNET_CADET_PortMessage *pmsg)
-{
- struct CadetClient *c = cls;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Closing port %s as requested by %s\n",
- GNUNET_h2s (&pmsg->port),
- GSC_2s (c));
- if (GNUNET_YES !=
- GNUNET_CONTAINER_multihashmap_remove (c->ports,
- &pmsg->port,
- c))
- {
- GNUNET_break (0);
- GNUNET_SERVICE_client_drop (c->client);
- return;
- }
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_remove (open_ports,
- &pmsg->port,
- c));
- GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Handler for requests for us creating a new channel to another peer and port.
- *
- * @param cls Identification of the client.
- * @param tcm The actual message.
- */
-static void
-handle_channel_create (void *cls,
- const struct GNUNET_CADET_LocalChannelCreateMessage *tcm)
-{
- struct CadetClient *c = cls;
- struct CadetChannel *ch;
-
- if (ntohl (tcm->ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
- {
- /* Channel ID not in allowed range. */
- GNUNET_break (0);
- GNUNET_SERVICE_client_drop (c->client);
- return;
- }
- ch = lookup_channel (c,
- tcm->ccn);
- if (NULL != ch)
- {
- /* Channel ID already in use. Not allowed. */
- GNUNET_break (0);
- GNUNET_SERVICE_client_drop (c->client);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "New channel to %s at port %s requested by %s\n",
- GNUNET_i2s (&tcm->peer),
- GNUNET_h2s (&tcm->port),
- GSC_2s (c));
-
- /* Create channel */
- ch = GCCH_channel_local_new (c,
- tcm->ccn,
- GCP_get (&tcm->peer,
- GNUNET_YES),
- &tcm->port,
- ntohl (tcm->opt));
- if (NULL == ch)
- {
- GNUNET_break (0);
- GNUNET_SERVICE_client_drop (c->client);
- return;
- }
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap32_put (c->channels,
- ntohl (tcm->ccn.channel_of_client),
- ch,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-
- GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Handler for requests of destroying an existing channel.
- *
- * @param cls client identification of the client
- * @param msg the actual message
- */
-static void
-handle_channel_destroy (void *cls,
- const struct GNUNET_CADET_LocalChannelDestroyMessage *msg)
-{
- struct CadetClient *c = cls;
- struct CadetChannel *ch;
-
- ch = lookup_channel (c,
- msg->ccn);
- if (NULL == ch)
- {
- /* Client attempted to destroy unknown channel.
- Can happen if the other side went down at the same time.*/
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "%s tried to destroy unknown channel %X\n",
- GSC_2s(c),
- (uint32_t) ntohl (msg->ccn.channel_of_client));
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "%s is destroying %s\n",
- GSC_2s(c),
- GCCH_2s (ch));
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap32_remove (c->channels,
- ntohl (msg->ccn.channel_of_client),
- ch));
- GCCH_channel_local_destroy (ch,
- c,
- msg->ccn);
- GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Check for client traffic data message is well-formed.
- *
- * @param cls identification of the client
- * @param msg the actual message
- * @return #GNUNET_OK if @a msg is OK, #GNUNET_SYSERR if not
- */
-static int
-check_local_data (void *cls,
- const struct GNUNET_CADET_LocalData *msg)
-{
- size_t payload_size;
- size_t payload_claimed_size;
- const char *buf;
- struct GNUNET_MessageHeader pa;
-
- /* FIXME: what is the format we shall allow for @a msg?
- ONE payload item or multiple? Seems current cadet_api
- at least in theory allows more than one. Next-gen
- cadet_api will likely no more, so we could then
- simplify this mess again. */
- /* Sanity check for message size */
- payload_size = ntohs (msg->header.size) - sizeof (*msg);
- buf = (const char *) &msg[1];
- while (payload_size >= sizeof (struct GNUNET_MessageHeader))
- {
- /* need to memcpy() for alignment */
- GNUNET_memcpy (&pa,
- buf,
- sizeof (pa));
- payload_claimed_size = ntohs (pa.size);
- if ( (payload_size < payload_claimed_size) ||
- (payload_claimed_size < sizeof (struct GNUNET_MessageHeader)) ||
- (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_claimed_size) )
- {
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Local data of %u total size had sub-message %u at %u with %u bytes\n",
- ntohs (msg->header.size),
- ntohs (pa.type),
- (unsigned int) (buf - (const char *) &msg[1]),
- (unsigned int) payload_claimed_size);
- return GNUNET_SYSERR;
- }
- payload_size -= payload_claimed_size;
- buf += payload_claimed_size;
- }
- if (0 != payload_size)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Handler for client payload traffic to be send on a channel to
- * another peer.
- *
- * @param cls identification of the client
- * @param msg the actual message
- */
-static void
-handle_local_data (void *cls,
- const struct GNUNET_CADET_LocalData *msg)
-{
- struct CadetClient *c = cls;
- struct CadetChannel *ch;
- size_t payload_size;
- const char *buf;
-
- ch = lookup_channel (c,
- msg->ccn);
- if (NULL == ch)
- {
- /* Channel does not exist (anymore) */
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "Dropping payload for channel %u from client (channel unknown, other endpoint may have disconnected)\n",
- (unsigned int) ntohl (msg->ccn.channel_of_client));
- GNUNET_SERVICE_client_continue (c->client);
- return;
- }
- payload_size = ntohs (msg->header.size) - sizeof (*msg);
- GNUNET_STATISTICS_update (stats,
- "# payload received from clients",
- payload_size,
- GNUNET_NO);
- buf = (const char *) &msg[1];
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Received %u bytes payload from %s for %s\n",
- (unsigned int) payload_size,
- GSC_2s (c),
- GCCH_2s (ch));
- if (GNUNET_OK !=
- GCCH_handle_local_data (ch,
- msg->ccn,
- buf,
- payload_size))
- {
- GNUNET_SERVICE_client_drop (c->client);
- return;
- }
- GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Handler for client's ACKs for payload traffic.
- *
- * @param cls identification of the client.
- * @param msg The actual message.
- */
-static void
-handle_local_ack (void *cls,
- const struct GNUNET_CADET_LocalAck *msg)
-{
- struct CadetClient *c = cls;
- struct CadetChannel *ch;
-
- ch = lookup_channel (c,
- msg->ccn);
- if (NULL == ch)
- {
- /* Channel does not exist (anymore) */
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "Ignoring local ACK for channel %u from client (channel unknown, other endpoint may have disconnected)\n",
- (unsigned int) ntohl (msg->ccn.channel_of_client));
- GNUNET_SERVICE_client_continue (c->client);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Got a local ACK from %s for %s\n",
- GSC_2s(c),
- GCCH_2s (ch));
- GCCH_handle_local_ack (ch,
- msg->ccn);
- GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * 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 CadetClient *c = cls;
- struct CadetPeer *p = value;
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_CADET_LocalInfoPeer *msg;
-
- env = GNUNET_MQ_msg (msg,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
- msg->destination = *peer;
- msg->paths = htons (GCP_count_paths (p));
- msg->tunnel = htons (NULL != GCP_get_tunnel (p,
- GNUNET_NO));
- GNUNET_MQ_send (c->mq,
- env);
- return GNUNET_YES;
-}
-
-
-/**
- * Handler for client's INFO PEERS request.
- *
- * @param cls Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_get_peers (void *cls,
- const struct GNUNET_MessageHeader *message)
-{
- struct CadetClient *c = cls;
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_MessageHeader *reply;
-
- GCP_iterate_all (&get_all_peers_iterator,
- c);
- env = GNUNET_MQ_msg (reply,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
- GNUNET_MQ_send (c->mq,
- env);
- GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Iterator over all paths of a peer to build an InfoPeer message.
- * Message contains blocks of peers, first not included.
- *
- * @param cls message queue for transmission
- * @param path Path itself
- * @param off offset of the peer on @a path
- * @return #GNUNET_YES if should keep iterating.
- * #GNUNET_NO otherwise.
- */
-static int
-path_info_iterator (void *cls,
- struct CadetPeerPath *path,
- unsigned int off)
-{
- struct GNUNET_MQ_Handle *mq = cls;
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_MessageHeader *resp;
- struct GNUNET_PeerIdentity *id;
- uint16_t path_size;
- unsigned int i;
- unsigned int path_length;
-
- path_length = GCPP_get_length (path);
- path_size = sizeof (struct GNUNET_PeerIdentity) * (path_length - 1);
- if (sizeof (*resp) + path_size > UINT16_MAX)
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "Path of %u entries is too long for info message\n",
- path_length);
- return GNUNET_YES;
- }
- env = GNUNET_MQ_msg_extra (resp,
- path_size,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
- id = (struct GNUNET_PeerIdentity *) &resp[1];
-
- /* Don't copy first peer. First peer is always the local one. Last
- * peer is always the destination (leave as 0, EOL).
- */
- for (i = 0; i < off; i++)
- id[i] = *GCP_get_id (GCPP_get_peer_at_offset (path,
- i + 1));
- GNUNET_MQ_send (mq,
- env);
- return GNUNET_YES;
-}
-
-
-/**
- * Handler for client's SHOW_PEER request.
- *
- * @param cls Identification of the client.
- * @param msg The actual message.
- */
-static void
-handle_show_peer (void *cls,
- const struct GNUNET_CADET_LocalInfo *msg)
-{
- struct CadetClient *c = cls;
- struct CadetPeer *p;
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_MessageHeader *resp;
-
- p = GCP_get (&msg->peer,
- GNUNET_NO);
- if (NULL != p)
- GCP_iterate_paths (p,
- &path_info_iterator,
- c->mq);
- /* Send message with 0/0 to indicate the end */
- env = GNUNET_MQ_msg (resp,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER_END);
- GNUNET_MQ_send (c->mq,
- env);
- GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * 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 a `struct CadetPeer`
- * @return #GNUNET_YES, to keep iterating.
- */
-static int
-get_all_tunnels_iterator (void *cls,
- const struct GNUNET_PeerIdentity *peer,
- void *value)
-{
- struct CadetClient *c = cls;
- struct CadetPeer *p = value;
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_CADET_LocalInfoTunnel *msg;
- struct CadetTunnel *t;
-
- t = GCP_get_tunnel (p,
- GNUNET_NO);
- if (NULL == t)
- return GNUNET_YES;
- env = GNUNET_MQ_msg (msg,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
- msg->destination = *peer;
- msg->channels = htonl (GCT_count_channels (t));
- msg->connections = htonl (GCT_count_any_connections (t));
- msg->cstate = htons (0);
- msg->estate = htons ((uint16_t) GCT_get_estate (t));
- GNUNET_MQ_send (c->mq,
- env);
- return GNUNET_YES;
-}
-
-
-/**
- * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS request.
- *
- * @param cls client Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_info_tunnels (void *cls,
- const struct GNUNET_MessageHeader *message)
-{
- struct CadetClient *c = cls;
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_MessageHeader *reply;
-
- GCP_iterate_all (&get_all_tunnels_iterator,
- c);
- env = GNUNET_MQ_msg (reply,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
- GNUNET_MQ_send (c->mq,
- env);
- GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Update the message with information about the connection.
- *
- * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
- * @param ct a connection about which we should store information in @a cls
- */
-static void
-iter_connection (void *cls,
- struct CadetTConnection *ct)
-{
- struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
- struct CadetConnection *cc = ct->cc;
- struct GNUNET_CADET_ConnectionTunnelIdentifier *h;
-
- h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
- h[msg->connections++] = *(GCC_get_id (cc));
-}
-
-
-/**
- * Update the message with information about the channel.
- *
- * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
- * @param ch a channel about which we should store information in @a cls
- */
-static void
-iter_channel (void *cls,
- struct CadetChannel *ch)
-{
- struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
- struct GNUNET_CADET_ConnectionTunnelIdentifier *h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
- struct GNUNET_CADET_ChannelTunnelNumber *chn
- = (struct GNUNET_CADET_ChannelTunnelNumber *) &h[msg->connections];
-
- chn[msg->channels++] = GCCH_get_id (ch);
-}
-
-
-/**
- * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL request.
- *
- * @param cls Identification of the client.
- * @param msg The actual message.
- */
-static void
-handle_info_tunnel (void *cls,
- const struct GNUNET_CADET_LocalInfo *msg)
-{
- struct CadetClient *c = cls;
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_CADET_LocalInfoTunnel *resp;
- struct CadetTunnel *t;
- struct CadetPeer *p;
- unsigned int ch_n;
- unsigned int c_n;
-
- p = GCP_get (&msg->peer,
- GNUNET_NO);
- t = GCP_get_tunnel (p,
- GNUNET_NO);
- if (NULL == t)
- {
- /* We don't know the tunnel */
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_CADET_LocalInfoTunnel *warn;
-
- LOG (GNUNET_ERROR_TYPE_INFO,
- "Tunnel to %s unknown\n",
- GNUNET_i2s_full (&msg->peer));
- env = GNUNET_MQ_msg (warn,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
- warn->destination = msg->peer;
- GNUNET_MQ_send (c->mq,
- env);
- GNUNET_SERVICE_client_continue (c->client);
- return;
- }
-
- /* Initialize context */
- ch_n = GCT_count_channels (t);
- c_n = GCT_count_any_connections (t);
- env = GNUNET_MQ_msg_extra (resp,
- c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier) +
- ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber),
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
- resp->destination = msg->peer;
- /* Do not reorder! #iter_channel needs counters in HBO! */
- GCT_iterate_connections (t,
- &iter_connection,
- resp);
- GCT_iterate_channels (t,
- &iter_channel,
- resp);
- resp->connections = htonl (resp->connections);
- resp->channels = htonl (resp->channels);
- resp->cstate = htons (0);
- resp->estate = htons (GCT_get_estate (t));
- GNUNET_MQ_send (c->mq,
- env);
- GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Iterator over all peers to dump info for each peer.
- *
- * @param cls Closure (unused).
- * @param peer Peer ID (tunnel remote peer).
- * @param value Peer info.
- *
- * @return #GNUNET_YES, to keep iterating.
- */
-static int
-show_peer_iterator (void *cls,
- const struct GNUNET_PeerIdentity *peer,
- void *value)
-{
- struct CadetPeer *p = value;
- struct CadetTunnel *t;
-
- t = GCP_get_tunnel (p,
- GNUNET_NO);
- if (NULL != t)
- GCT_debug (t,
- GNUNET_ERROR_TYPE_ERROR);
- LOG (GNUNET_ERROR_TYPE_ERROR, "\n");
- return GNUNET_YES;
-}
-
-
-/**
- * Handler for client's INFO_DUMP request.
- *
- * @param cls Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_info_dump (void *cls,
- const struct GNUNET_MessageHeader *message)
-{
- struct CadetClient *c = cls;
-
- LOG (GNUNET_ERROR_TYPE_INFO,
- "Received dump info request from client %u\n",
- c->id);
-
- LOG (GNUNET_ERROR_TYPE_ERROR,
- "*************************** DUMP START ***************************\n");
- for (struct CadetClient *ci = clients_head;
- NULL != ci;
- ci = ci->next)
- {
- LOG (GNUNET_ERROR_TYPE_ERROR,
- "Client %u (%p), handle: %p, ports: %u, channels: %u\n",
- ci->id,
- ci,
- ci->client,
- (NULL != c->ports)
- ? GNUNET_CONTAINER_multihashmap_size (ci->ports)
- : 0,
- GNUNET_CONTAINER_multihashmap32_size (ci->channels));
- }
- LOG (GNUNET_ERROR_TYPE_ERROR, "***************************\n");
- GCP_iterate_all (&show_peer_iterator,
- NULL);
-
- LOG (GNUNET_ERROR_TYPE_ERROR,
- "**************************** DUMP END ****************************\n");
-
- GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-
-/**
- * Callback called when a client connects to the service.
- *
- * @param cls closure for the service
- * @param client the new client that connected to the service
- * @param mq the message queue used to send messages to the client
- * @return @a c
- */
-static void *
-client_connect_cb (void *cls,
- struct GNUNET_SERVICE_Client *client,
- struct GNUNET_MQ_Handle *mq)
-{
- struct CadetClient *c;
-
- c = GNUNET_new (struct CadetClient);
- c->client = client;
- c->mq = mq;
- c->id = next_client_id++; /* overflow not important: just for debug */
- c->channels
- = GNUNET_CONTAINER_multihashmap32_create (32);
- GNUNET_CONTAINER_DLL_insert (clients_head,
- clients_tail,
- c);
- GNUNET_STATISTICS_update (stats,
- "# clients",
- +1,
- GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "%s connected\n",
- GSC_2s (c));
- return c;
-}
-
-
-/**
- * A channel was destroyed by the other peer. Tell our client.
- *
- * @param c client that lost a channel
- * @param ccn channel identification number for the client
- * @param ch the channel object
- */
-void
-GSC_handle_remote_channel_destroy (struct CadetClient *c,
- struct GNUNET_CADET_ClientChannelNumber ccn,
- struct CadetChannel *ch)
-{
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_CADET_LocalChannelDestroyMessage *tdm;
-
- env = GNUNET_MQ_msg (tdm,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
- tdm->ccn = ccn;
- GSC_send_to_client (c,
- env);
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap32_remove (c->channels,
- ntohl (ccn.channel_of_client),
- ch));
-}
-
-
-/**
- * A client that created a loose channel that was not bound to a port
- * disconnected, drop it from the #loose_channels list.
- *
- * @param port the port the channel was trying to bind to
- * @param ch the channel that was lost
- */
-void
-GSC_drop_loose_channel (const struct GNUNET_HashCode *port,
- struct CadetChannel *ch)
-{
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_remove (loose_channels,
- port,
- ch));
-}
-
-
-/**
- * Iterator for deleting each channel whose client endpoint disconnected.
- *
- * @param cls Closure (client that has disconnected).
- * @param key The local channel id in host byte order
- * @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 CadetClient *c = cls;
- struct GNUNET_CADET_ClientChannelNumber ccn;
- struct CadetChannel *ch = value;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Destroying %s, due to %s disconnecting.\n",
- GCCH_2s (ch),
- GSC_2s (c));
- ccn.channel_of_client = htonl (key);
- GCCH_channel_local_destroy (ch,
- c,
- ccn);
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap32_remove (c->channels,
- key,
- ch));
- return GNUNET_OK;
-}
-
-
-/**
- * Remove client's ports from the global hashmap on disconnect.
- *
- * @param cls Closure (unused).
- * @param key the port.
- * @param value the `struct CadetClient` to remove
- * @return #GNUNET_OK, keep iterating.
- */
-static int
-client_release_ports (void *cls,
- const struct GNUNET_HashCode *key,
- void *value)
-{
- struct CadetClient *c = value;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Closing port %s due to %s disconnect.\n",
- GNUNET_h2s (key),
- GSC_2s (c));
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_remove (open_ports,
- key,
- value));
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_remove (c->ports,
- key,
- value));
- return GNUNET_OK;
-}
-
-
-/**
- * Callback called when a client disconnected from the service
- *
- * @param cls closure for the service
- * @param client the client that disconnected
- * @param internal_cls should be equal to @a c
- */
-static void
-client_disconnect_cb (void *cls,
- struct GNUNET_SERVICE_Client *client,
- void *internal_cls)
-{
- struct CadetClient *c = internal_cls;
-
- GNUNET_assert (c->client == client);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "%s is disconnecting.\n",
- GSC_2s (c));
- if (NULL != c->channels)
- {
- GNUNET_CONTAINER_multihashmap32_iterate (c->channels,
- &channel_destroy_iterator,
- c);
- GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (c->channels));
- GNUNET_CONTAINER_multihashmap32_destroy (c->channels);
- }
- if (NULL != c->ports)
- {
- GNUNET_CONTAINER_multihashmap_iterate (c->ports,
- &client_release_ports,
- c);
- GNUNET_CONTAINER_multihashmap_destroy (c->ports);
- }
- GNUNET_CONTAINER_DLL_remove (clients_head,
- clients_tail,
- c);
- GNUNET_STATISTICS_update (stats,
- "# clients",
- -1,
- GNUNET_NO);
- GNUNET_free (c);
- if ( (NULL == clients_head) &&
- (GNUNET_YES == shutting_down) )
- shutdown_rest ();
-}
-
-
-/**
- * Setup CADET internals.
- *
- * @param cls closure
- * @param server the initialized server
- * @param c configuration to use
- */
-static void
-run (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *c,
- struct GNUNET_SERVICE_Handle *service)
-{
- cfg = c;
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (c,
- "CADET",
- "RATCHET_MESSAGES",
- &ratchet_messages))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
- "CADET",
- "RATCHET_MESSAGES",
- "needs to be a number");
- ratchet_messages = 64;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (c,
- "CADET",
- "RATCHET_TIME",
- &ratchet_time))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
- "CADET",
- "RATCHET_TIME",
- "need delay value");
- ratchet_time = GNUNET_TIME_UNIT_HOURS;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (c,
- "CADET",
- "REFRESH_CONNECTION_TIME",
- &keepalive_period))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
- "CADET",
- "REFRESH_CONNECTION_TIME",
- "need delay value");
- keepalive_period = GNUNET_TIME_UNIT_MINUTES;
- }
- 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");
- }
- my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
- if (NULL == my_private_key)
- {
- GNUNET_break (0);
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- GNUNET_CRYPTO_eddsa_key_get_public (my_private_key,
- &my_full_id.public_key);
- stats = GNUNET_STATISTICS_create ("cadet",
- c);
- GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
- NULL);
- ats_ch = GNUNET_ATS_connectivity_init (c);
- /* FIXME: optimize code to allow GNUNET_YES here! */
- open_ports = GNUNET_CONTAINER_multihashmap_create (16,
- GNUNET_NO);
- loose_channels = GNUNET_CONTAINER_multihashmap_create (16,
- GNUNET_NO);
- peers = GNUNET_CONTAINER_multipeermap_create (16,
- GNUNET_YES);
- connections = GNUNET_CONTAINER_multishortmap_create (256,
- GNUNET_YES);
- GCH_init (c);
- GCD_init (c);
- GCO_init (c);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "CADET started for peer %s\n",
- GNUNET_i2s (&my_full_id));
-
-}
-
-
-/**
- * Define "main" method using service macro.
- */
-GNUNET_SERVICE_MAIN
-("cadet",
- GNUNET_SERVICE_OPTION_NONE,
- &run,
- &client_connect_cb,
- &client_disconnect_cb,
- NULL,
- GNUNET_MQ_hd_fixed_size (port_open,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN,
- struct GNUNET_CADET_PortMessage,
- NULL),
- GNUNET_MQ_hd_fixed_size (port_close,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE,
- struct GNUNET_CADET_PortMessage,
- NULL),
- GNUNET_MQ_hd_fixed_size (channel_create,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE,
- struct GNUNET_CADET_LocalChannelCreateMessage,
- NULL),
- GNUNET_MQ_hd_fixed_size (channel_destroy,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY,
- struct GNUNET_CADET_LocalChannelDestroyMessage,
- NULL),
- GNUNET_MQ_hd_var_size (local_data,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
- struct GNUNET_CADET_LocalData,
- NULL),
- GNUNET_MQ_hd_fixed_size (local_ack,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
- struct GNUNET_CADET_LocalAck,
- NULL),
- GNUNET_MQ_hd_fixed_size (get_peers,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
- struct GNUNET_MessageHeader,
- NULL),
- GNUNET_MQ_hd_fixed_size (show_peer,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
- struct GNUNET_CADET_LocalInfo,
- NULL),
- GNUNET_MQ_hd_fixed_size (info_tunnels,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
- struct GNUNET_MessageHeader,
- NULL),
- GNUNET_MQ_hd_fixed_size (info_tunnel,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
- struct GNUNET_CADET_LocalInfo,
- NULL),
- GNUNET_MQ_hd_fixed_size (info_dump,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP,
- struct GNUNET_MessageHeader,
- NULL),
- GNUNET_MQ_handler_end ());
-
-/* end of gnunet-service-cadet-new.c */
diff --git a/src/cadet/gnunet-service-cadet-new_channel.c b/src/cadet/gnunet-service-cadet-new_channel.c
deleted file mode 100644
index 43c9058167..0000000000
--- a/src/cadet/gnunet-service-cadet-new_channel.c
+++ /dev/null
@@ -1,2040 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2001-2017 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/gnunet-service-cadet-new_channel.c
- * @brief logical links between CADET clients
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * TODO:
- * - Congestion/flow control:
- * + estimate max bandwidth using bursts and use to for CONGESTION CONTROL!
- * (and figure out how/where to use this!)
- * + figure out flow control without ACKs (unreliable traffic!)
- * - revisit handling of 'unbuffered' traffic!
- * (need to push down through tunnel into connection selection)
- * - revisit handling of 'buffered' traffic: 4 is a rather small buffer; maybe
- * reserve more bits in 'options' to allow for buffer size control?
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "cadet.h"
-#include "gnunet_statistics_service.h"
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_channel.h"
-#include "gnunet-service-cadet-new_connection.h"
-#include "gnunet-service-cadet-new_tunnels.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_paths.h"
-
-#define LOG(level,...) GNUNET_log_from (level,"cadet-chn",__VA_ARGS__)
-
-/**
- * How long do we initially wait before retransmitting?
- */
-#define CADET_INITIAL_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 250)
-
-/**
- * How long do we wait before dropping state about incoming
- * connection to closed port?
- */
-#define TIMEOUT_CLOSED_PORT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
-
-/**
- * How long do we wait at least before retransmitting ever?
- */
-#define MIN_RTT_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 75)
-
-/**
- * Maximum message ID into the future we accept for out-of-order messages.
- * If the message is more than this into the future, we drop it. This is
- * important both to detect values that are actually in the past, as well
- * as to limit adversarially triggerable memory consumption.
- *
- * Note that right now we have "max_pending_messages = 4" hard-coded in
- * the logic below, so a value of 4 would suffice here. But we plan to
- * allow larger windows in the future...
- */
-#define MAX_OUT_OF_ORDER_DISTANCE 1024
-
-
-/**
- * All the states a channel can be in.
- */
-enum CadetChannelState
-{
- /**
- * Uninitialized status, should never appear in operation.
- */
- CADET_CHANNEL_NEW,
-
- /**
- * Channel is to a port that is not open, we're waiting for the
- * port to be opened.
- */
- CADET_CHANNEL_LOOSE,
-
- /**
- * CHANNEL_OPEN message sent, waiting for CHANNEL_OPEN_ACK.
- */
- CADET_CHANNEL_OPEN_SENT,
-
- /**
- * Connection confirmed, ready to carry traffic.
- */
- CADET_CHANNEL_READY
-};
-
-
-/**
- * Info needed to retry a message in case it gets lost.
- * Note that we DO use this structure also for unreliable
- * messages.
- */
-struct CadetReliableMessage
-{
- /**
- * Double linked list, FIFO style
- */
- struct CadetReliableMessage *next;
-
- /**
- * Double linked list, FIFO style
- */
- struct CadetReliableMessage *prev;
-
- /**
- * Which channel is this message in?
- */
- struct CadetChannel *ch;
-
- /**
- * Entry in the tunnels queue for this message, NULL if it has left
- * the tunnel. Used to cancel transmission in case we receive an
- * ACK in time.
- */
- struct CadetTunnelQueueEntry *qe;
-
- /**
- * Data message we are trying to send.
- */
- struct GNUNET_CADET_ChannelAppDataMessage *data_message;
-
- /**
- * How soon should we retry if we fail to get an ACK?
- * Messages in the queue are sorted by this value.
- */
- struct GNUNET_TIME_Absolute next_retry;
-
- /**
- * How long do we wait for an ACK after transmission?
- * Use for the back-off calculation.
- */
- struct GNUNET_TIME_Relative retry_delay;
-
- /**
- * Time when we first successfully transmitted the message
- * (that is, set @e num_transmissions to 1).
- */
- struct GNUNET_TIME_Absolute first_transmission_time;
-
- /**
- * Identifier of the connection that this message took when it
- * was first transmitted. Only useful if @e num_transmissions is 1.
- */
- struct GNUNET_CADET_ConnectionTunnelIdentifier connection_taken;
-
- /**
- * How often was this message transmitted? #GNUNET_SYSERR if there
- * was an error transmitting the message, #GNUNET_NO if it was not
- * yet transmitted ever, otherwise the number of (re) transmissions.
- */
- int num_transmissions;
-
-};
-
-
-/**
- * List of received out-of-order data messages.
- */
-struct CadetOutOfOrderMessage
-{
- /**
- * Double linked list, FIFO style
- */
- struct CadetOutOfOrderMessage *next;
-
- /**
- * Double linked list, FIFO style
- */
- struct CadetOutOfOrderMessage *prev;
-
- /**
- * ID of the message (messages up to this point needed
- * before we give this one to the client).
- */
- struct ChannelMessageIdentifier mid;
-
- /**
- * The envelope with the payload of the out-of-order message
- */
- struct GNUNET_MQ_Envelope *env;
-
-};
-
-
-/**
- * Client endpoint of a `struct CadetChannel`. A channel may be a
- * loopback channel, in which case it has two of these endpoints.
- * Note that flow control also is required in both directions.
- */
-struct CadetChannelClient
-{
- /**
- * Client handle. Not by itself sufficient to designate
- * the client endpoint, as the same client handle may
- * be used for both the owner and the destination, and
- * we thus also need the channel ID to identify the client.
- */
- struct CadetClient *c;
-
- /**
- * Head of DLL of messages received out of order or while client was unready.
- */
- struct CadetOutOfOrderMessage *head_recv;
-
- /**
- * Tail DLL of messages received out of order or while client was unready.
- */
- struct CadetOutOfOrderMessage *tail_recv;
-
- /**
- * Local tunnel number for this client.
- * (if owner >= #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI,
- * otherwise < #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
- */
- struct GNUNET_CADET_ClientChannelNumber ccn;
-
- /**
- * Number of entries currently in @a head_recv DLL.
- */
- unsigned int num_recv;
-
- /**
- * Can we send data to the client?
- */
- int client_ready;
-
-};
-
-
-/**
- * Struct containing all information regarding a channel to a remote client.
- */
-struct CadetChannel
-{
- /**
- * Tunnel this channel is in.
- */
- struct CadetTunnel *t;
-
- /**
- * Client owner of the tunnel, if any.
- * (Used if this channel represends the initiating end of the tunnel.)
- */
- struct CadetChannelClient *owner;
-
- /**
- * Client destination of the tunnel, if any.
- * (Used if this channel represents the listening end of the tunnel.)
- */
- struct CadetChannelClient *dest;
-
- /**
- * Last entry in the tunnel's queue relating to control messages
- * (#GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN or
- * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK). Used to cancel
- * transmission in case we receive updated information.
- */
- struct CadetTunnelQueueEntry *last_control_qe;
-
- /**
- * Head of DLL of messages sent and not yet ACK'd.
- */
- struct CadetReliableMessage *head_sent;
-
- /**
- * Tail of DLL of messages sent and not yet ACK'd.
- */
- struct CadetReliableMessage *tail_sent;
-
- /**
- * Task to resend/poll in case no ACK is received.
- */
- struct GNUNET_SCHEDULER_Task *retry_control_task;
-
- /**
- * Task to resend/poll in case no ACK is received.
- */
- struct GNUNET_SCHEDULER_Task *retry_data_task;
-
- /**
- * Last time the channel was used
- */
- struct GNUNET_TIME_Absolute timestamp;
-
- /**
- * Destination port of the channel.
- */
- struct GNUNET_HashCode port;
-
- /**
- * Counter for exponential backoff.
- */
- struct GNUNET_TIME_Relative retry_time;
-
- /**
- * Bitfield of already-received messages past @e mid_recv.
- */
- uint64_t mid_futures;
-
- /**
- * Next MID expected for incoming traffic.
- */
- struct ChannelMessageIdentifier mid_recv;
-
- /**
- * Next MID to use for outgoing traffic.
- */
- struct ChannelMessageIdentifier mid_send;
-
- /**
- * Total (reliable) messages pending ACK for this channel.
- */
- unsigned int pending_messages;
-
- /**
- * Maximum (reliable) messages pending ACK for this channel
- * before we throttle the client.
- */
- unsigned int max_pending_messages;
-
- /**
- * Number identifying this channel in its tunnel.
- */
- struct GNUNET_CADET_ChannelTunnelNumber ctn;
-
- /**
- * Channel state.
- */
- enum CadetChannelState state;
-
- /**
- * Count how many ACKs we skipped, used to prevent long
- * sequences of ACK skipping.
- */
- unsigned int skip_ack_series;
-
- /**
- * Is the tunnel bufferless (minimum latency)?
- */
- int nobuffer;
-
- /**
- * Is the tunnel reliable?
- */
- int reliable;
-
- /**
- * Is the tunnel out-of-order?
- */
- int out_of_order;
-
- /**
- * Is this channel a loopback channel, where the destination is us again?
- */
- int is_loopback;
-
- /**
- * Flag to signal the destruction of the channel. If this is set to
- * #GNUNET_YES the channel will be destroyed once the queue is
- * empty.
- */
- int destroy;
-
-};
-
-
-/**
- * Get the static string for identification of the channel.
- *
- * @param ch Channel.
- *
- * @return Static string with the channel IDs.
- */
-const char *
-GCCH_2s (const struct CadetChannel *ch)
-{
- static char buf[128];
-
- GNUNET_snprintf (buf,
- sizeof (buf),
- "Channel %s:%s ctn:%X(%X/%X)",
- (GNUNET_YES == ch->is_loopback)
- ? "loopback"
- : GNUNET_i2s (GCP_get_id (GCT_get_destination (ch->t))),
- GNUNET_h2s (&ch->port),
- ch->ctn,
- (NULL == ch->owner) ? 0 : ntohl (ch->owner->ccn.channel_of_client),
- (NULL == ch->dest) ? 0 : ntohl (ch->dest->ccn.channel_of_client));
- return buf;
-}
-
-
-/**
- * Get the channel's public ID.
- *
- * @param ch Channel.
- *
- * @return ID used to identify the channel with the remote peer.
- */
-struct GNUNET_CADET_ChannelTunnelNumber
-GCCH_get_id (const struct CadetChannel *ch)
-{
- return ch->ctn;
-}
-
-
-/**
- * Release memory associated with @a ccc
- *
- * @param ccc data structure to clean up
- */
-static void
-free_channel_client (struct CadetChannelClient *ccc)
-{
- struct CadetOutOfOrderMessage *com;
-
- while (NULL != (com = ccc->head_recv))
- {
- GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
- ccc->tail_recv,
- com);
- ccc->num_recv--;
- GNUNET_MQ_discard (com->env);
- GNUNET_free (com);
- }
- GNUNET_free (ccc);
-}
-
-
-/**
- * Destroy the given channel.
- *
- * @param ch channel to destroy
- */
-static void
-channel_destroy (struct CadetChannel *ch)
-{
- struct CadetReliableMessage *crm;
-
- while (NULL != (crm = ch->head_sent))
- {
- GNUNET_assert (ch == crm->ch);
- if (NULL != crm->qe)
- {
- GCT_send_cancel (crm->qe);
- crm->qe = NULL;
- }
- GNUNET_CONTAINER_DLL_remove (ch->head_sent,
- ch->tail_sent,
- crm);
- GNUNET_free (crm->data_message);
- GNUNET_free (crm);
- }
- if (NULL != ch->owner)
- {
- free_channel_client (ch->owner);
- ch->owner = NULL;
- }
- if (NULL != ch->dest)
- {
- free_channel_client (ch->dest);
- ch->dest = NULL;
- }
- if (NULL != ch->last_control_qe)
- {
- GCT_send_cancel (ch->last_control_qe);
- ch->last_control_qe = NULL;
- }
- if (NULL != ch->retry_data_task)
- {
- GNUNET_SCHEDULER_cancel (ch->retry_data_task);
- ch->retry_data_task = NULL;
- }
- if (NULL != ch->retry_control_task)
- {
- GNUNET_SCHEDULER_cancel (ch->retry_control_task);
- ch->retry_control_task = NULL;
- }
- if (GNUNET_NO == ch->is_loopback)
- {
- GCT_remove_channel (ch->t,
- ch,
- ch->ctn);
- ch->t = NULL;
- }
- GNUNET_free (ch);
-}
-
-
-/**
- * Send a channel create message.
- *
- * @param cls Channel for which to send.
- */
-static void
-send_channel_open (void *cls);
-
-
-/**
- * Function called once the tunnel confirms that we sent the
- * create message. Delays for a bit until we retry.
- *
- * @param cls our `struct CadetChannel`.
- * @param cid identifier of the connection within the tunnel, NULL
- * if transmission failed
- */
-static void
-channel_open_sent_cb (void *cls,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
- struct CadetChannel *ch = cls;
-
- GNUNET_assert (NULL != ch->last_control_qe);
- ch->last_control_qe = NULL;
- ch->retry_time = GNUNET_TIME_STD_BACKOFF (ch->retry_time);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sent CADET_CHANNEL_OPEN on %s, retrying in %s\n",
- GCCH_2s (ch),
- GNUNET_STRINGS_relative_time_to_string (ch->retry_time,
- GNUNET_YES));
- ch->retry_control_task
- = GNUNET_SCHEDULER_add_delayed (ch->retry_time,
- &send_channel_open,
- ch);
-}
-
-
-/**
- * Send a channel open message.
- *
- * @param cls Channel for which to send.
- */
-static void
-send_channel_open (void *cls)
-{
- struct CadetChannel *ch = cls;
- struct GNUNET_CADET_ChannelOpenMessage msgcc;
- uint32_t options;
-
- ch->retry_control_task = NULL;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sending CHANNEL_OPEN message for %s\n",
- GCCH_2s (ch));
- options = 0;
- if (ch->nobuffer)
- options |= GNUNET_CADET_OPTION_NOBUFFER;
- if (ch->reliable)
- options |= GNUNET_CADET_OPTION_RELIABLE;
- if (ch->out_of_order)
- options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
- msgcc.header.size = htons (sizeof (msgcc));
- msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN);
- msgcc.opt = htonl (options);
- msgcc.port = ch->port;
- msgcc.ctn = ch->ctn;
- ch->state = CADET_CHANNEL_OPEN_SENT;
- if (NULL != ch->last_control_qe)
- GCT_send_cancel (ch->last_control_qe);
- ch->last_control_qe = GCT_send (ch->t,
- &msgcc.header,
- &channel_open_sent_cb,
- ch);
- GNUNET_assert (NULL == ch->retry_control_task);
-}
-
-
-/**
- * Function called once and only once after a channel was bound
- * to its tunnel via #GCT_add_channel() is ready for transmission.
- * Note that this is only the case for channels that this peer
- * initiates, as for incoming channels we assume that they are
- * ready for transmission immediately upon receiving the open
- * message. Used to bootstrap the #GCT_send() process.
- *
- * @param ch the channel for which the tunnel is now ready
- */
-void
-GCCH_tunnel_up (struct CadetChannel *ch)
-{
- GNUNET_assert (NULL == ch->retry_control_task);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Tunnel up, sending CHANNEL_OPEN on %s now\n",
- GCCH_2s (ch));
- ch->retry_control_task
- = GNUNET_SCHEDULER_add_now (&send_channel_open,
- ch);
-}
-
-
-/**
- * Create a new channel.
- *
- * @param owner local client owning the channel
- * @param ccn local number of this channel at the @a owner
- * @param destination peer to which we should build the channel
- * @param port desired port at @a destination
- * @param options options for the channel
- * @return handle to the new channel
- */
-struct CadetChannel *
-GCCH_channel_local_new (struct CadetClient *owner,
- struct GNUNET_CADET_ClientChannelNumber ccn,
- struct CadetPeer *destination,
- const struct GNUNET_HashCode *port,
- uint32_t options)
-{
- struct CadetChannel *ch;
- struct CadetChannelClient *ccco;
-
- ccco = GNUNET_new (struct CadetChannelClient);
- ccco->c = owner;
- ccco->ccn = ccn;
- ccco->client_ready = GNUNET_YES;
-
- ch = GNUNET_new (struct CadetChannel);
- ch->mid_recv.mid = htonl (1); /* The OPEN_ACK counts as message 0! */
- ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
- ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
- ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
- ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
- ch->owner = ccco;
- ch->port = *port;
- if (0 == memcmp (&my_full_id,
- GCP_get_id (destination),
- sizeof (struct GNUNET_PeerIdentity)))
- {
- struct CadetClient *c;
-
- ch->is_loopback = GNUNET_YES;
- c = GNUNET_CONTAINER_multihashmap_get (open_ports,
- port);
- if (NULL == c)
- {
- /* port closed, wait for it to possibly open */
- ch->state = CADET_CHANNEL_LOOSE;
- (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
- port,
- ch,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Created loose incoming loopback channel to port %s\n",
- GNUNET_h2s (&ch->port));
- }
- else
- {
- GCCH_bind (ch,
- c);
- }
- }
- else
- {
- ch->t = GCP_get_tunnel (destination,
- GNUNET_YES);
- ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
- ch->ctn = GCT_add_channel (ch->t,
- ch);
- }
- GNUNET_STATISTICS_update (stats,
- "# channels",
- 1,
- GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Created channel to port %s at peer %s for %s using %s\n",
- GNUNET_h2s (port),
- GCP_2s (destination),
- GSC_2s (owner),
- (GNUNET_YES == ch->is_loopback) ? "loopback" : GCT_2s (ch->t));
- return ch;
-}
-
-
-/**
- * We had an incoming channel to a port that is closed.
- * It has not been opened for a while, drop it.
- *
- * @param cls the channel to drop
- */
-static void
-timeout_closed_cb (void *cls)
-{
- struct CadetChannel *ch = cls;
-
- ch->retry_control_task = NULL;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Closing incoming channel to port %s from peer %s due to timeout\n",
- GNUNET_h2s (&ch->port),
- GCP_2s (GCT_get_destination (ch->t)));
- channel_destroy (ch);
-}
-
-
-/**
- * Create a new channel based on a request coming in over the network.
- *
- * @param t tunnel to the remote peer
- * @param ctn identifier of this channel in the tunnel
- * @param port desired local port
- * @param options options for the channel
- * @return handle to the new channel
- */
-struct CadetChannel *
-GCCH_channel_incoming_new (struct CadetTunnel *t,
- struct GNUNET_CADET_ChannelTunnelNumber ctn,
- const struct GNUNET_HashCode *port,
- uint32_t options)
-{
- struct CadetChannel *ch;
- struct CadetClient *c;
-
- ch = GNUNET_new (struct CadetChannel);
- ch->port = *port;
- ch->t = t;
- ch->ctn = ctn;
- ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
- ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
- ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
- ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
- ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
- GNUNET_STATISTICS_update (stats,
- "# channels",
- 1,
- GNUNET_NO);
-
- c = GNUNET_CONTAINER_multihashmap_get (open_ports,
- port);
- if (NULL == c)
- {
- /* port closed, wait for it to possibly open */
- ch->state = CADET_CHANNEL_LOOSE;
- (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
- port,
- ch,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
- GNUNET_assert (NULL == ch->retry_control_task);
- ch->retry_control_task
- = GNUNET_SCHEDULER_add_delayed (TIMEOUT_CLOSED_PORT,
- &timeout_closed_cb,
- ch);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Created loose incoming channel to port %s from peer %s\n",
- GNUNET_h2s (&ch->port),
- GCP_2s (GCT_get_destination (ch->t)));
- }
- else
- {
- GCCH_bind (ch,
- c);
- }
- GNUNET_STATISTICS_update (stats,
- "# channels",
- 1,
- GNUNET_NO);
- return ch;
-}
-
-
-/**
- * Function called once the tunnel confirms that we sent the
- * ACK message. Just remembers it was sent, we do not expect
- * ACKs for ACKs ;-).
- *
- * @param cls our `struct CadetChannel`.
- * @param cid identifier of the connection within the tunnel, NULL
- * if transmission failed
- */
-static void
-send_ack_cb (void *cls,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
- struct CadetChannel *ch = cls;
-
- GNUNET_assert (NULL != ch->last_control_qe);
- ch->last_control_qe = NULL;
-}
-
-
-/**
- * Compute and send the current #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK to the other peer.
- *
- * @param ch channel to send the #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK for
- */
-static void
-send_channel_data_ack (struct CadetChannel *ch)
-{
- struct GNUNET_CADET_ChannelDataAckMessage msg;
-
- if (GNUNET_NO == ch->reliable)
- return; /* no ACKs */
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK);
- msg.header.size = htons (sizeof (msg));
- msg.ctn = ch->ctn;
- msg.mid.mid = htonl (ntohl (ch->mid_recv.mid));
- msg.futures = GNUNET_htonll (ch->mid_futures);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sending DATA_ACK %u:%llX via %s\n",
- (unsigned int) ntohl (msg.mid.mid),
- (unsigned long long) ch->mid_futures,
- GCCH_2s (ch));
- if (NULL != ch->last_control_qe)
- GCT_send_cancel (ch->last_control_qe);
- ch->last_control_qe = GCT_send (ch->t,
- &msg.header,
- &send_ack_cb,
- ch);
-}
-
-
-/**
- * Send our initial #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK to the client confirming that the
- * connection is up.
- *
- * @param cls the `struct CadetChannel`
- */
-static void
-send_open_ack (void *cls)
-{
- struct CadetChannel *ch = cls;
- struct GNUNET_CADET_ChannelManageMessage msg;
-
- ch->retry_control_task = NULL;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sending CHANNEL_OPEN_ACK on %s\n",
- GCCH_2s (ch));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK);
- msg.header.size = htons (sizeof (msg));
- msg.reserved = htonl (0);
- msg.ctn = ch->ctn;
- if (NULL != ch->last_control_qe)
- GCT_send_cancel (ch->last_control_qe);
- ch->last_control_qe = GCT_send (ch->t,
- &msg.header,
- &send_ack_cb,
- ch);
-}
-
-
-/**
- * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
- * this channel. If the binding was successful, (re)transmit the
- * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
- *
- * @param ch channel that got the duplicate open
- * @param cti identifier of the connection that delivered the message
- */
-void
-GCCH_handle_duplicate_open (struct CadetChannel *ch,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
-{
- if (NULL == ch->dest)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Ignoring duplicate CHANNEL_OPEN on %s: port is closed\n",
- GCCH_2s (ch));
- return;
- }
- if (NULL != ch->retry_control_task)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Ignoring duplicate CHANNEL_OPEN on %s: control message is pending\n",
- GCCH_2s (ch));
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Retransmitting CHANNEL_OPEN_ACK on %s\n",
- GCCH_2s (ch));
- ch->retry_control_task
- = GNUNET_SCHEDULER_add_now (&send_open_ack,
- ch);
-}
-
-
-/**
- * Send a #GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK to the client to solicit more messages.
- *
- * @param ch channel the ack is for
- * @param to_owner #GNUNET_YES to send to owner,
- * #GNUNET_NO to send to dest
- */
-static void
-send_ack_to_client (struct CadetChannel *ch,
- int to_owner)
-{
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_CADET_LocalAck *ack;
- struct CadetChannelClient *ccc;
-
- ccc = (GNUNET_YES == to_owner) ? ch->owner : ch->dest;
- if (NULL == ccc)
- {
- /* This can happen if we are just getting ACKs after
- our local client already disconnected. */
- GNUNET_assert (GNUNET_YES == ch->destroy);
- return;
- }
- env = GNUNET_MQ_msg (ack,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
- ack->ccn = ccc->ccn;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sending CADET_LOCAL_ACK to %s (%s) at ccn %X (%u/%u pending)\n",
- GSC_2s (ccc->c),
- (GNUNET_YES == to_owner) ? "owner" : "dest",
- ntohl (ack->ccn.channel_of_client),
- ch->pending_messages,
- ch->max_pending_messages);
- GSC_send_to_client (ccc->c,
- env);
-}
-
-
-/**
- * A client is bound to the port that we have a channel
- * open to. Send the acknowledgement for the connection
- * request and establish the link with the client.
- *
- * @param ch open incoming channel
- * @param c client listening on the respective port
- */
-void
-GCCH_bind (struct CadetChannel *ch,
- struct CadetClient *c)
-{
- uint32_t options;
- struct CadetChannelClient *cccd;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Binding %s from %s to port %s of %s\n",
- GCCH_2s (ch),
- GCT_2s (ch->t),
- GNUNET_h2s (&ch->port),
- GSC_2s (c));
- if (NULL != ch->retry_control_task)
- {
- /* there might be a timeout task here */
- GNUNET_SCHEDULER_cancel (ch->retry_control_task);
- ch->retry_control_task = NULL;
- }
- options = 0;
- if (ch->nobuffer)
- options |= GNUNET_CADET_OPTION_NOBUFFER;
- if (ch->reliable)
- options |= GNUNET_CADET_OPTION_RELIABLE;
- if (ch->out_of_order)
- options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
- cccd = GNUNET_new (struct CadetChannelClient);
- GNUNET_assert (NULL == ch->dest);
- ch->dest = cccd;
- cccd->c = c;
- cccd->client_ready = GNUNET_YES;
- cccd->ccn = GSC_bind (c,
- ch,
- (GNUNET_YES == ch->is_loopback)
- ? GCP_get (&my_full_id,
- GNUNET_YES)
- : GCT_get_destination (ch->t),
- &ch->port,
- options);
- GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
- GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
- ch->mid_recv.mid = htonl (1); /* The OPEN counts as message 0! */
- if (GNUNET_YES == ch->is_loopback)
- {
- ch->state = CADET_CHANNEL_OPEN_SENT;
- GCCH_handle_channel_open_ack (ch,
- NULL);
- }
- else
- {
- /* notify other peer that we accepted the connection */
- ch->state = CADET_CHANNEL_READY;
- ch->retry_control_task
- = GNUNET_SCHEDULER_add_now (&send_open_ack,
- ch);
- }
- /* give client it's initial supply of ACKs */
- GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
- GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
- for (unsigned int i=0;i<ch->max_pending_messages;i++)
- send_ack_to_client (ch,
- GNUNET_NO);
-}
-
-
-/**
- * One of our clients has disconnected, tell the other one that we
- * are finished. Done asynchronously to avoid concurrent modification
- * issues if this is the same client.
- *
- * @param cls the `struct CadetChannel` where one of the ends is now dead
- */
-static void
-signal_remote_destroy_cb (void *cls)
-{
- struct CadetChannel *ch = cls;
- struct CadetChannelClient *ccc;
-
- /* Find which end is left... */
- ch->retry_control_task = NULL;
- ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
- GSC_handle_remote_channel_destroy (ccc->c,
- ccc->ccn,
- ch);
- channel_destroy (ch);
-}
-
-
-/**
- * Destroy locally created channel. Called by the local client, so no
- * need to tell the client.
- *
- * @param ch channel to destroy
- * @param c client that caused the destruction
- * @param ccn client number of the client @a c
- */
-void
-GCCH_channel_local_destroy (struct CadetChannel *ch,
- struct CadetClient *c,
- struct GNUNET_CADET_ClientChannelNumber ccn)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "%s asks for destruction of %s\n",
- GSC_2s (c),
- GCCH_2s (ch));
- GNUNET_assert (NULL != c);
- if ( (NULL != ch->owner) &&
- (c == ch->owner->c) &&
- (ccn.channel_of_client == ch->owner->ccn.channel_of_client) )
- {
- free_channel_client (ch->owner);
- ch->owner = NULL;
- }
- else if ( (NULL != ch->dest) &&
- (c == ch->dest->c) &&
- (ccn.channel_of_client == ch->dest->ccn.channel_of_client) )
- {
- free_channel_client (ch->dest);
- ch->dest = NULL;
- }
- else
- {
- GNUNET_assert (0);
- }
-
- if (GNUNET_YES == ch->destroy)
- {
- /* other end already destroyed, with the local client gone, no need
- to finish transmissions, just destroy immediately. */
- channel_destroy (ch);
- return;
- }
- if ( (NULL != ch->head_sent) &&
- ( (NULL != ch->owner) ||
- (NULL != ch->dest) ) )
- {
- /* Wait for other end to destroy us as well,
- and otherwise allow send queue to be transmitted first */
- ch->destroy = GNUNET_YES;
- return;
- }
- if ( (GNUNET_YES == ch->is_loopback) &&
- ( (NULL != ch->owner) ||
- (NULL != ch->dest) ) )
- {
- if (NULL != ch->retry_control_task)
- GNUNET_SCHEDULER_cancel (ch->retry_control_task);
- ch->retry_control_task
- = GNUNET_SCHEDULER_add_now (&signal_remote_destroy_cb,
- ch);
- return;
- }
- if (GNUNET_NO == ch->is_loopback)
- {
- /* If the we ever sent the CHANNEL_CREATE, we need to send a destroy message. */
- switch (ch->state)
- {
- case CADET_CHANNEL_NEW:
- /* We gave up on a channel that we created as a client to a remote
- target, but that never went anywhere. Nothing to do here. */
- break;
- case CADET_CHANNEL_LOOSE:
- GSC_drop_loose_channel (&ch->port,
- ch);
- break;
- default:
- GCT_send_channel_destroy (ch->t,
- ch->ctn);
- }
- }
- /* Nothing left to do, just finish destruction */
- channel_destroy (ch);
-}
-
-
-/**
- * We got an acknowledgement for the creation of the channel
- * (the port is open on the other side). Begin transmissions.
- *
- * @param ch channel to destroy
- * @param cti identifier of the connection that delivered the message
- */
-void
-GCCH_handle_channel_open_ack (struct CadetChannel *ch,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
-{
- switch (ch->state)
- {
- case CADET_CHANNEL_NEW:
- /* this should be impossible */
- GNUNET_break (0);
- break;
- case CADET_CHANNEL_LOOSE:
- /* This makes no sense. */
- GNUNET_break_op (0);
- break;
- case CADET_CHANNEL_OPEN_SENT:
- if (NULL == ch->owner)
- {
- /* We're not the owner, wrong direction! */
- GNUNET_break_op (0);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Received CHANNEL_OPEN_ACK for waiting %s, entering READY state\n",
- GCCH_2s (ch));
- if (NULL != ch->retry_control_task) /* can be NULL if ch->is_loopback */
- {
- GNUNET_SCHEDULER_cancel (ch->retry_control_task);
- ch->retry_control_task = NULL;
- }
- ch->state = CADET_CHANNEL_READY;
- /* On first connect, send client as many ACKs as we allow messages
- to be buffered! */
- for (unsigned int i=0;i<ch->max_pending_messages;i++)
- send_ack_to_client (ch,
- GNUNET_YES);
- break;
- case CADET_CHANNEL_READY:
- /* duplicate ACK, maybe we retried the CREATE. Ignore. */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Received duplicate channel OPEN_ACK for %s\n",
- GCCH_2s (ch));
- GNUNET_STATISTICS_update (stats,
- "# duplicate CREATE_ACKs",
- 1,
- GNUNET_NO);
- break;
- }
-}
-
-
-/**
- * Test if element @a e1 comes before element @a e2.
- *
- * @param cls closure, to a flag where we indicate duplicate packets
- * @param m1 a message of to sort
- * @param m2 another message to sort
- * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
- */
-static int
-is_before (void *cls,
- struct CadetOutOfOrderMessage *m1,
- struct CadetOutOfOrderMessage *m2)
-{
- int *duplicate = cls;
- uint32_t v1 = ntohl (m1->mid.mid);
- uint32_t v2 = ntohl (m2->mid.mid);
- uint32_t delta;
-
- delta = v2 - v1;
- if (0 == delta)
- *duplicate = GNUNET_YES;
- if (delta > (uint32_t) INT_MAX)
- {
- /* in overflow range, we can safely assume we wrapped around */
- return GNUNET_NO;
- }
- else
- {
- /* result is small, thus v2 > v1, thus m1 < m2 */
- return GNUNET_YES;
- }
-}
-
-
-/**
- * We got payload data for a channel. Pass it on to the client
- * and send an ACK to the other end (once flow control allows it!)
- *
- * @param ch channel that got data
- * @param cti identifier of the connection that delivered the message
- * @param msg message that was received
- */
-void
-GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
- const struct GNUNET_CADET_ChannelAppDataMessage *msg)
-{
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_CADET_LocalData *ld;
- struct CadetChannelClient *ccc;
- size_t payload_size;
- struct CadetOutOfOrderMessage *com;
- int duplicate;
- uint32_t mid_min;
- uint32_t mid_max;
- uint32_t mid_msg;
- uint32_t delta;
-
- GNUNET_assert (GNUNET_NO == ch->is_loopback);
- if ( (GNUNET_YES == ch->destroy) &&
- (NULL == ch->owner) &&
- (NULL == ch->dest) )
- {
- /* This client is gone, but we still have messages to send to
- the other end (which is why @a ch is not yet dead). However,
- we cannot pass messages to our client anymore. */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Dropping incoming payload on %s as this end is already closed\n",
- GCCH_2s (ch));
- /* send back DESTROY notification to stop further retransmissions! */
- GCT_send_channel_destroy (ch->t,
- ch->ctn);
- return;
- }
- payload_size = ntohs (msg->header.size) - sizeof (*msg);
- env = GNUNET_MQ_msg_extra (ld,
- payload_size,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
- ld->ccn = (NULL == ch->dest) ? ch->owner->ccn : ch->dest->ccn;
- GNUNET_memcpy (&ld[1],
- &msg[1],
- payload_size);
- ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
- if ( (GNUNET_YES == ccc->client_ready) &&
- ( (GNUNET_YES == ch->out_of_order) ||
- (msg->mid.mid == ch->mid_recv.mid) ) )
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Giving %u bytes of payload with MID %u from %s to client %s\n",
- (unsigned int) payload_size,
- ntohl (msg->mid.mid),
- GCCH_2s (ch),
- GSC_2s (ccc->c));
- ccc->client_ready = GNUNET_NO;
- GSC_send_to_client (ccc->c,
- env);
- ch->mid_recv.mid = htonl (1 + ntohl (ch->mid_recv.mid));
- ch->mid_futures >>= 1;
- send_channel_data_ack (ch);
- return;
- }
-
- if (GNUNET_YES == ch->reliable)
- {
- /* check if message ought to be dropped because it is ancient/too distant/duplicate */
- mid_min = ntohl (ch->mid_recv.mid);
- mid_max = mid_min + ch->max_pending_messages;
- mid_msg = ntohl (msg->mid.mid);
- if ( ( (uint32_t) (mid_msg - mid_min) > ch->max_pending_messages) ||
- ( (uint32_t) (mid_max - mid_msg) > ch->max_pending_messages) )
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "%s at %u drops ancient or far-future message %u\n",
- GCCH_2s (ch),
- (unsigned int) mid_min,
- ntohl (msg->mid.mid));
-
- GNUNET_STATISTICS_update (stats,
- "# duplicate DATA (ancient or future)",
- 1,
- GNUNET_NO);
- GNUNET_MQ_discard (env);
- send_channel_data_ack (ch);
- return;
- }
- /* mark bit for future ACKs */
- delta = mid_msg - mid_min - 1; /* overflow/underflow are OK here */
- if (delta < 64)
- {
- if (0 != (ch->mid_futures & (1LLU << delta)))
- {
- /* Duplicate within the queue, drop also */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
- (unsigned int) payload_size,
- GCCH_2s (ch),
- ntohl (msg->mid.mid));
- GNUNET_STATISTICS_update (stats,
- "# duplicate DATA",
- 1,
- GNUNET_NO);
- GNUNET_MQ_discard (env);
- send_channel_data_ack (ch);
- return;
- }
- ch->mid_futures |= (1LLU << delta);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Marked bit %llX for mid %u (base: %u); now: %llX\n",
- (1LLU << delta),
- mid_msg,
- mid_min,
- ch->mid_futures);
- }
- }
- else /* ! ch->reliable */
- {
- /* Channel is unreliable, so we do not ACK. But we also cannot
- allow buffering everything, so check if we have space... */
- if (ccc->num_recv >= ch->max_pending_messages)
- {
- struct CadetOutOfOrderMessage *drop;
-
- /* Yep, need to drop. Drop the oldest message in
- the buffer. */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Queue full due slow client on %s, dropping oldest message\n",
- GCCH_2s (ch));
- GNUNET_STATISTICS_update (stats,
- "# messages dropped due to slow client",
- 1,
- GNUNET_NO);
- drop = ccc->head_recv;
- GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
- ccc->tail_recv,
- drop);
- ccc->num_recv--;
- GNUNET_MQ_discard (drop->env);
- GNUNET_free (drop);
- }
- }
-
- /* Insert message into sorted out-of-order queue */
- com = GNUNET_new (struct CadetOutOfOrderMessage);
- com->mid = msg->mid;
- com->env = env;
- duplicate = GNUNET_NO;
- GNUNET_CONTAINER_DLL_insert_sorted (struct CadetOutOfOrderMessage,
- is_before,
- &duplicate,
- ccc->head_recv,
- ccc->tail_recv,
- com);
- ccc->num_recv++;
- if (GNUNET_YES == duplicate)
- {
- /* Duplicate within the queue, drop also (this is not covered by
- the case above if "delta" >= 64, which could be the case if
- max_pending_messages is also >= 64 or if our client is unready
- and we are seeing retransmissions of the message our client is
- blocked on. */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
- (unsigned int) payload_size,
- GCCH_2s (ch),
- ntohl (msg->mid.mid));
- GNUNET_STATISTICS_update (stats,
- "# duplicate DATA",
- 1,
- GNUNET_NO);
- GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
- ccc->tail_recv,
- com);
- ccc->num_recv--;
- GNUNET_MQ_discard (com->env);
- GNUNET_free (com);
- send_channel_data_ack (ch);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Queued %s payload of %u bytes on %s-%X(%p) (mid %u, need %u first)\n",
- (GNUNET_YES == ccc->client_ready)
- ? "out-of-order"
- : "client-not-ready",
- (unsigned int) payload_size,
- GCCH_2s (ch),
- ntohl (ccc->ccn.channel_of_client),
- ccc,
- ntohl (msg->mid.mid),
- ntohl (ch->mid_recv.mid));
- /* NOTE: this ACK we _could_ skip, as the packet is out-of-order and
- the sender may already be transmitting the previous one. Needs
- experimental evaluation to see if/when this ACK helps or
- hurts. (We might even want another option.) */
- send_channel_data_ack (ch);
-}
-
-
-/**
- * Function called once the tunnel has sent one of our messages.
- * If the message is unreliable, simply frees the `crm`. If the
- * message was reliable, calculate retransmission time and
- * wait for ACK (or retransmit).
- *
- * @param cls the `struct CadetReliableMessage` that was sent
- * @param cid identifier of the connection within the tunnel, NULL
- * if transmission failed
- */
-static void
-data_sent_cb (void *cls,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
-
-
-/**
- * We need to retry a transmission, the last one took too long to
- * be acknowledged.
- *
- * @param cls the `struct CadetChannel` where we need to retransmit
- */
-static void
-retry_transmission (void *cls)
-{
- struct CadetChannel *ch = cls;
- struct CadetReliableMessage *crm = ch->head_sent;
-
- ch->retry_data_task = NULL;
- GNUNET_assert (NULL == crm->qe);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Retrying transmission on %s of message %u\n",
- GCCH_2s (ch),
- (unsigned int) ntohl (crm->data_message->mid.mid));
- crm->qe = GCT_send (ch->t,
- &crm->data_message->header,
- &data_sent_cb,
- crm);
- GNUNET_assert (NULL == ch->retry_data_task);
-}
-
-
-/**
- * We got an PLAINTEXT_DATA_ACK for a message in our queue, remove it from
- * the queue and tell our client that it can send more.
- *
- * @param ch the channel that got the PLAINTEXT_DATA_ACK
- * @param cti identifier of the connection that delivered the message
- * @param crm the message that got acknowledged
- */
-static void
-handle_matching_ack (struct CadetChannel *ch,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
- struct CadetReliableMessage *crm)
-{
- GNUNET_CONTAINER_DLL_remove (ch->head_sent,
- ch->tail_sent,
- crm);
- ch->pending_messages--;
- GNUNET_assert (ch->pending_messages < ch->max_pending_messages);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Received DATA_ACK on %s for message %u (%u ACKs pending)\n",
- GCCH_2s (ch),
- (unsigned int) ntohl (crm->data_message->mid.mid),
- ch->pending_messages);
- if (NULL != crm->qe)
- {
- GCT_send_cancel (crm->qe);
- crm->qe = NULL;
- }
- if ( (1 == crm->num_transmissions) &&
- (NULL != cti) )
- {
- GCC_ack_observed (cti);
- if (0 == memcmp (cti,
- &crm->connection_taken,
- sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier)))
- {
- GCC_latency_observed (cti,
- GNUNET_TIME_absolute_get_duration (crm->first_transmission_time));
- }
- }
- GNUNET_free (crm->data_message);
- GNUNET_free (crm);
- send_ack_to_client (ch,
- (NULL == ch->owner)
- ? GNUNET_NO
- : GNUNET_YES);
-}
-
-
-/**
- * We got an acknowledgement for payload data for a channel.
- * Possibly resume transmissions.
- *
- * @param ch channel that got the ack
- * @param cti identifier of the connection that delivered the message
- * @param ack details about what was received
- */
-void
-GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
- const struct GNUNET_CADET_ChannelDataAckMessage *ack)
-{
- struct CadetReliableMessage *crm;
- struct CadetReliableMessage *crmn;
- int found;
- uint32_t mid_base;
- uint64_t mid_mask;
- unsigned int delta;
-
- GNUNET_break (GNUNET_NO == ch->is_loopback);
- if (GNUNET_NO == ch->reliable)
- {
- /* not expecting ACKs on unreliable channel, odd */
- GNUNET_break_op (0);
- return;
- }
- /* mid_base is the MID of the next message that the
- other peer expects (i.e. that is missing!), everything
- LOWER (but excluding mid_base itself) was received. */
- mid_base = ntohl (ack->mid.mid);
- mid_mask = GNUNET_htonll (ack->futures);
- found = GNUNET_NO;
- for (crm = ch->head_sent;
- NULL != crm;
- crm = crmn)
- {
- crmn = crm->next;
- delta = (unsigned int) (ntohl (crm->data_message->mid.mid) - mid_base);
- if (delta >= UINT_MAX - ch->max_pending_messages)
- {
- /* overflow, means crm was a bit in the past, so this ACK counts for it. */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Got DATA_ACK with base %u satisfying past message %u on %s\n",
- (unsigned int) mid_base,
- ntohl (crm->data_message->mid.mid),
- GCCH_2s (ch));
- handle_matching_ack (ch,
- cti,
- crm);
- found = GNUNET_YES;
- continue;
- }
- delta--;
- if (delta >= 64)
- continue;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Testing bit %llX for mid %u (base: %u)\n",
- (1LLU << delta),
- ntohl (crm->data_message->mid.mid),
- mid_base);
- if (0 != (mid_mask & (1LLU << delta)))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Got DATA_ACK with mask for %u on %s\n",
- ntohl (crm->data_message->mid.mid),
- GCCH_2s (ch));
- handle_matching_ack (ch,
- cti,
- crm);
- found = GNUNET_YES;
- }
- }
- if (GNUNET_NO == found)
- {
- /* ACK for message we already dropped, might have been a
- duplicate ACK? Ignore. */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Duplicate DATA_ACK on %s, ignoring\n",
- GCCH_2s (ch));
- GNUNET_STATISTICS_update (stats,
- "# duplicate DATA_ACKs",
- 1,
- GNUNET_NO);
- return;
- }
- if (NULL != ch->retry_data_task)
- {
- GNUNET_SCHEDULER_cancel (ch->retry_data_task);
- ch->retry_data_task = NULL;
- }
- if ( (NULL != ch->head_sent) &&
- (NULL == ch->head_sent->qe) )
- ch->retry_data_task
- = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
- &retry_transmission,
- ch);
-}
-
-
-/**
- * Destroy channel, based on the other peer closing the
- * connection. Also needs to remove this channel from
- * the tunnel.
- *
- * @param ch channel to destroy
- * @param cti identifier of the connection that delivered the message,
- * NULL if we are simulating receiving a destroy due to shutdown
- */
-void
-GCCH_handle_remote_destroy (struct CadetChannel *ch,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
-{
- struct CadetChannelClient *ccc;
-
- GNUNET_assert (GNUNET_NO == ch->is_loopback);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Received remote channel DESTROY for %s\n",
- GCCH_2s (ch));
- if (GNUNET_YES == ch->destroy)
- {
- /* Local client already gone, this is instant-death. */
- channel_destroy (ch);
- return;
- }
- ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
- if ( (NULL != ccc) &&
- (NULL != ccc->head_recv) )
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "Lost end of transmission due to remote shutdown on %s\n",
- GCCH_2s (ch));
- /* FIXME: change API to notify client about truncated transmission! */
- }
- ch->destroy = GNUNET_YES;
- if (NULL != ccc)
- GSC_handle_remote_channel_destroy (ccc->c,
- ccc->ccn,
- ch);
- channel_destroy (ch);
-}
-
-
-/**
- * Test if element @a e1 comes before element @a e2.
- *
- * @param cls closure, to a flag where we indicate duplicate packets
- * @param crm1 an element of to sort
- * @param crm2 another element to sort
- * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
- */
-static int
-cmp_crm_by_next_retry (void *cls,
- struct CadetReliableMessage *crm1,
- struct CadetReliableMessage *crm2)
-{
- if (crm1->next_retry.abs_value_us <
- crm2->next_retry.abs_value_us)
- return GNUNET_YES;
- return GNUNET_NO;
-}
-
-
-/**
- * Function called once the tunnel has sent one of our messages.
- * If the message is unreliable, simply frees the `crm`. If the
- * message was reliable, calculate retransmission time and
- * wait for ACK (or retransmit).
- *
- * @param cls the `struct CadetReliableMessage` that was sent
- * @param cid identifier of the connection within the tunnel, NULL
- * if transmission failed
- */
-static void
-data_sent_cb (void *cls,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
- struct CadetReliableMessage *crm = cls;
- struct CadetChannel *ch = crm->ch;
-
- GNUNET_assert (GNUNET_NO == ch->is_loopback);
- GNUNET_assert (NULL != crm->qe);
- crm->qe = NULL;
- GNUNET_CONTAINER_DLL_remove (ch->head_sent,
- ch->tail_sent,
- crm);
- if (GNUNET_NO == ch->reliable)
- {
- GNUNET_free (crm->data_message);
- GNUNET_free (crm);
- ch->pending_messages--;
- send_ack_to_client (ch,
- (NULL == ch->owner)
- ? GNUNET_NO
- : GNUNET_YES);
- return;
- }
- if (NULL == cid)
- {
- /* There was an error sending. */
- crm->num_transmissions = GNUNET_SYSERR;
- }
- else if (GNUNET_SYSERR != crm->num_transmissions)
- {
- /* Increment transmission counter, and possibly store @a cid
- if this was the first transmission. */
- crm->num_transmissions++;
- if (1 == crm->num_transmissions)
- {
- crm->first_transmission_time = GNUNET_TIME_absolute_get ();
- crm->connection_taken = *cid;
- GCC_ack_expected (cid);
- }
- }
- if ( (0 == crm->retry_delay.rel_value_us) &&
- (NULL != cid) )
- {
- struct CadetConnection *cc = GCC_lookup (cid);
-
- if (NULL != cc)
- crm->retry_delay = GCC_get_metrics (cc)->aged_latency;
- else
- crm->retry_delay = ch->retry_time;
- }
- crm->retry_delay = GNUNET_TIME_STD_BACKOFF (crm->retry_delay);
- crm->retry_delay = GNUNET_TIME_relative_max (crm->retry_delay,
- MIN_RTT_DELAY);
- crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay);
-
- GNUNET_CONTAINER_DLL_insert_sorted (struct CadetReliableMessage,
- cmp_crm_by_next_retry,
- NULL,
- ch->head_sent,
- ch->tail_sent,
- crm);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Message %u sent, next transmission on %s in %s\n",
- (unsigned int) ntohl (crm->data_message->mid.mid),
- GCCH_2s (ch),
- GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (ch->head_sent->next_retry),
- GNUNET_YES));
- if (NULL == ch->head_sent->qe)
- {
- if (NULL != ch->retry_data_task)
- GNUNET_SCHEDULER_cancel (ch->retry_data_task);
- ch->retry_data_task
- = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
- &retry_transmission,
- ch);
- }
-}
-
-
-/**
- * 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 sender_ccn ccn of the sender
- * @param buf payload to transmit.
- * @param buf_len number of bytes in @a buf
- * @return #GNUNET_OK if everything goes well,
- * #GNUNET_SYSERR in case of an error.
- */
-int
-GCCH_handle_local_data (struct CadetChannel *ch,
- struct GNUNET_CADET_ClientChannelNumber sender_ccn,
- const char *buf,
- size_t buf_len)
-{
- struct CadetReliableMessage *crm;
-
- if (ch->pending_messages > ch->max_pending_messages)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_YES == ch->destroy)
- {
- /* we are going down, drop messages */
- return GNUNET_OK;
- }
- ch->pending_messages++;
-
- if (GNUNET_YES == ch->is_loopback)
- {
- struct CadetChannelClient *receiver;
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_CADET_LocalData *ld;
- int ack_to_owner;
-
- env = GNUNET_MQ_msg_extra (ld,
- buf_len,
- GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
- if ( (NULL != ch->owner) &&
- (sender_ccn.channel_of_client ==
- ch->owner->ccn.channel_of_client) )
- {
- receiver = ch->dest;
- ack_to_owner = GNUNET_YES;
- }
- else if ( (NULL != ch->dest) &&
- (sender_ccn.channel_of_client ==
- ch->dest->ccn.channel_of_client) )
- {
- receiver = ch->owner;
- ack_to_owner = GNUNET_NO;
- }
- else
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- GNUNET_assert (NULL != receiver);
- ld->ccn = receiver->ccn;
- GNUNET_memcpy (&ld[1],
- buf,
- buf_len);
- if (GNUNET_YES == receiver->client_ready)
- {
- ch->pending_messages--;
- GSC_send_to_client (receiver->c,
- env);
- send_ack_to_client (ch,
- ack_to_owner);
- }
- else
- {
- struct CadetOutOfOrderMessage *oom;
-
- oom = GNUNET_new (struct CadetOutOfOrderMessage);
- oom->env = env;
- GNUNET_CONTAINER_DLL_insert_tail (receiver->head_recv,
- receiver->tail_recv,
- oom);
- receiver->num_recv++;
- }
- return GNUNET_OK;
- }
-
- /* Everything is correct, send the message. */
- crm = GNUNET_malloc (sizeof (*crm));
- crm->ch = ch;
- crm->data_message = GNUNET_malloc (sizeof (struct GNUNET_CADET_ChannelAppDataMessage)
- + buf_len);
- crm->data_message->header.size = htons (sizeof (struct GNUNET_CADET_ChannelAppDataMessage) + buf_len);
- crm->data_message->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA);
- ch->mid_send.mid = htonl (ntohl (ch->mid_send.mid) + 1);
- crm->data_message->mid = ch->mid_send;
- crm->data_message->ctn = ch->ctn;
- GNUNET_memcpy (&crm->data_message[1],
- buf,
- buf_len);
- GNUNET_CONTAINER_DLL_insert_tail (ch->head_sent,
- ch->tail_sent,
- crm);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sending message %u from local client to %s with %u bytes\n",
- ntohl (crm->data_message->mid.mid),
- GCCH_2s (ch),
- buf_len);
- if (NULL != ch->retry_data_task)
- {
- GNUNET_SCHEDULER_cancel (ch->retry_data_task);
- ch->retry_data_task = NULL;
- }
- crm->qe = GCT_send (ch->t,
- &crm->data_message->header,
- &data_sent_cb,
- crm);
- GNUNET_assert (NULL == ch->retry_data_task);
- return GNUNET_OK;
-}
-
-
-/**
- * Handle ACK from client on local channel. Means the client is ready
- * for more data, see if we have any for it.
- *
- * @param ch channel to destroy
- * @param client_ccn ccn of the client sending the ack
- */
-void
-GCCH_handle_local_ack (struct CadetChannel *ch,
- struct GNUNET_CADET_ClientChannelNumber client_ccn)
-{
- struct CadetChannelClient *ccc;
- struct CadetOutOfOrderMessage *com;
-
- if ( (NULL != ch->owner) &&
- (ch->owner->ccn.channel_of_client == client_ccn.channel_of_client) )
- ccc = ch->owner;
- else if ( (NULL != ch->dest) &&
- (ch->dest->ccn.channel_of_client == client_ccn.channel_of_client) )
- ccc = ch->dest;
- else
- GNUNET_assert (0);
- ccc->client_ready = GNUNET_YES;
- com = ccc->head_recv;
- if (NULL == com)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Got LOCAL_ACK, %s-%X ready to receive more data, but none pending on %s-%X(%p)!\n",
- GSC_2s (ccc->c),
- ntohl (client_ccn.channel_of_client),
- GCCH_2s (ch),
- ntohl (ccc->ccn.channel_of_client),
- ccc);
- return; /* none pending */
- }
- if (GNUNET_YES == ch->is_loopback)
- {
- int to_owner;
-
- /* Messages are always in-order, just send */
- GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
- ccc->tail_recv,
- com);
- ccc->num_recv--;
- GSC_send_to_client (ccc->c,
- com->env);
- /* Notify sender that we can receive more */
- if ( (NULL != ch->owner) &&
- (ccc->ccn.channel_of_client ==
- ch->owner->ccn.channel_of_client) )
- {
- to_owner = GNUNET_NO;
- }
- else
- {
- GNUNET_assert ( (NULL != ch->dest) &&
- (ccc->ccn.channel_of_client ==
- ch->dest->ccn.channel_of_client) );
- to_owner = GNUNET_YES;
- }
- send_ack_to_client (ch,
- to_owner);
- GNUNET_free (com);
- return;
- }
-
- if ( (com->mid.mid != ch->mid_recv.mid) &&
- (GNUNET_NO == ch->out_of_order) &&
- (GNUNET_YES == ch->reliable) )
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Got LOCAL_ACK, %s-%X ready to receive more data (but next one is out-of-order %u vs. %u)!\n",
- GSC_2s (ccc->c),
- ntohl (ccc->ccn.channel_of_client),
- ntohl (com->mid.mid),
- ntohl (ch->mid_recv.mid));
- return; /* missing next one in-order */
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Got LOCAL_ACK, giving payload message %u to %s-%X on %s\n",
- ntohl (com->mid.mid),
- GSC_2s (ccc->c),
- ntohl (ccc->ccn.channel_of_client),
- GCCH_2s (ch));
-
- /* all good, pass next message to client */
- GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
- ccc->tail_recv,
- com);
- ccc->num_recv--;
- /* FIXME: if unreliable, this is not aggressive
- enough, as it would be OK to have lost some! */
-
- ch->mid_recv.mid = htonl (1 + ntohl (com->mid.mid));
- ch->mid_futures >>= 1; /* equivalent to division by 2 */
- ccc->client_ready = GNUNET_NO;
- GSC_send_to_client (ccc->c,
- com->env);
- GNUNET_free (com);
- send_channel_data_ack (ch);
- if (NULL != ccc->head_recv)
- return;
- if (GNUNET_NO == ch->destroy)
- return;
- GCT_send_channel_destroy (ch->t,
- ch->ctn);
- channel_destroy (ch);
-}
-
-
-#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-chn",__VA_ARGS__)
-
-
-/**
- * Log channel info.
- *
- * @param ch Channel.
- * @param level Debug level to use.
- */
-void
-GCCH_debug (struct CadetChannel *ch,
- enum GNUNET_ErrorType level)
-{
- int do_log;
-
- do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
- "cadet-chn",
- __FILE__, __FUNCTION__, __LINE__);
- if (0 == do_log)
- return;
-
- if (NULL == ch)
- {
- LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n");
- return;
- }
- LOG2 (level,
- "CHN %s:%X (%p)\n",
- GCT_2s (ch->t),
- ch->ctn,
- ch);
- if (NULL != ch->owner)
- {
- LOG2 (level,
- "CHN origin %s ready %s local-id: %u\n",
- GSC_2s (ch->owner->c),
- ch->owner->client_ready ? "YES" : "NO",
- ntohl (ch->owner->ccn.channel_of_client));
- }
- if (NULL != ch->dest)
- {
- LOG2 (level,
- "CHN destination %s ready %s local-id: %u\n",
- GSC_2s (ch->dest->c),
- ch->dest->client_ready ? "YES" : "NO",
- ntohl (ch->dest->ccn.channel_of_client));
- }
- LOG2 (level,
- "CHN Message IDs recv: %d (%LLX), send: %d\n",
- ntohl (ch->mid_recv.mid),
- (unsigned long long) ch->mid_futures,
- ntohl (ch->mid_send.mid));
-}
-
-
-
-/* end of gnunet-service-cadet-new_channel.c */
diff --git a/src/cadet/gnunet-service-cadet-new_channel.h b/src/cadet/gnunet-service-cadet-new_channel.h
deleted file mode 100644
index 5167305a6c..0000000000
--- a/src/cadet/gnunet-service-cadet-new_channel.h
+++ /dev/null
@@ -1,262 +0,0 @@
-
-/*
- This file is part of GNUnet.
- Copyright (C) 2001-2017 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new_channel.h
- * @brief GNUnet CADET service with encryption
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#ifndef GNUNET_SERVICE_CADET_CHANNEL_H
-#define GNUNET_SERVICE_CADET_CHANNEL_H
-
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "cadet_protocol.h"
-
-
-/**
- * A channel is a bidirectional connection between two CADET
- * clients. Communiation can be reliable, unreliable, in-order
- * or out-of-order. One client is the "local" client, this
- * one initiated the connection. The other client is the
- * "incoming" client, this one listened on a port to accept
- * the connection from the "local" client.
- */
-struct CadetChannel;
-
-
-/**
- * Get the static string for identification of the channel.
- *
- * @param ch Channel.
- *
- * @return Static string with the channel IDs.
- */
-const char *
-GCCH_2s (const struct CadetChannel *ch);
-
-
-/**
- * Log channel info.
- *
- * @param ch Channel.
- * @param level Debug level to use.
- */
-void
-GCCH_debug (struct CadetChannel *ch,
- enum GNUNET_ErrorType level);
-
-
-/**
- * Get the channel's public ID.
- *
- * @param ch Channel.
- *
- * @return ID used to identify the channel with the remote peer.
- */
-struct GNUNET_CADET_ChannelTunnelNumber
-GCCH_get_id (const struct CadetChannel *ch);
-
-
-/**
- * Create a new channel.
- *
- * @param owner local client owning the channel
- * @param owner_id local chid of this channel at the @a owner
- * @param destination peer to which we should build the channel
- * @param port desired port at @a destination
- * @param options options for the channel
- * @return handle to the new channel
- */
-struct CadetChannel *
-GCCH_channel_local_new (struct CadetClient *owner,
- struct GNUNET_CADET_ClientChannelNumber owner_id,
- struct CadetPeer *destination,
- const struct GNUNET_HashCode *port,
- uint32_t options);
-
-
-/**
- * A client is bound to the port that we have a channel
- * open to. Send the acknowledgement for the connection
- * request and establish the link with the client.
- *
- * @param ch open incoming channel
- * @param c client listening on the respective port
- */
-void
-GCCH_bind (struct CadetChannel *ch,
- struct CadetClient *c);
-
-
-/**
- * Destroy locally created channel. Called by the
- * local client, so no need to tell the client.
- *
- * @param ch channel to destroy
- * @param c client that caused the destruction
- * @param ccn client number of the client @a c
- */
-void
-GCCH_channel_local_destroy (struct CadetChannel *ch,
- struct CadetClient *c,
- struct GNUNET_CADET_ClientChannelNumber ccn);
-
-
-/**
- * Function called once and only once after a channel was bound
- * to its tunnel via #GCT_add_channel() is ready for transmission.
- * Note that this is only the case for channels that this peer
- * initiates, as for incoming channels we assume that they are
- * ready for transmission immediately upon receiving the open
- * message. Used to bootstrap the #GCT_send() process.
- *
- * @param ch the channel for which the tunnel is now ready
- */
-void
-GCCH_tunnel_up (struct CadetChannel *ch);
-
-
-/**
- * Create a new channel based on a request coming in over the network.
- *
- * @param t tunnel to the remote peer
- * @param chid identifier of this channel in the tunnel
- * @param origin peer to who initiated the channel
- * @param port desired local port
- * @param options options for the channel
- * @return handle to the new channel
- */
-struct CadetChannel *
-GCCH_channel_incoming_new (struct CadetTunnel *t,
- struct GNUNET_CADET_ChannelTunnelNumber chid,
- const struct GNUNET_HashCode *port,
- uint32_t options);
-
-
-/**
- * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
- * this channel. If the binding was successful, (re)transmit the
- * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
- *
- * @param ch channel that got the duplicate open
- * @param cti identifier of the connection that delivered the message
- */
-void
-GCCH_handle_duplicate_open (struct CadetChannel *ch,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
-
-
-
-/**
- * We got payload data for a channel. Pass it on to the client.
- *
- * @param ch channel that got data
- * @param cti identifier of the connection that delivered the message
- * @param msg message that was received
- */
-void
-GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
- const struct GNUNET_CADET_ChannelAppDataMessage *msg);
-
-
-/**
- * We got an acknowledgement for payload data for a channel.
- * Possibly resume transmissions.
- *
- * @param ch channel that got the ack
- * @param cti identifier of the connection that delivered the message
- * @param ack details about what was received
- */
-void
-GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
- const struct GNUNET_CADET_ChannelDataAckMessage *ack);
-
-
-/**
- * We got an acknowledgement for the creation of the channel
- * (the port is open on the other side). Begin transmissions.
- *
- * @param ch channel to destroy
- * @param cti identifier of the connection that delivered the message,
- * NULL if the ACK was inferred because we got payload or are on loopback
- */
-void
-GCCH_handle_channel_open_ack (struct CadetChannel *ch,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
-
-
-/**
- * Destroy channel, based on the other peer closing the
- * connection. Also needs to remove this channel from
- * the tunnel.
- *
- * FIXME: need to make it possible to defer destruction until we have
- * received all messages up to the destroy, and right now the destroy
- * message (and this API) fails to give is the information we need!
- *
- * FIXME: also need to know if the other peer got a destroy from
- * us before!
- *
- * @param ch channel to destroy
- * @param cti identifier of the connection that delivered the message,
- * NULL during shutdown
- */
-void
-GCCH_handle_remote_destroy (struct CadetChannel *ch,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
-
-
-/**
- * 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 sender_ccn ccn of the sender
- * @param buf payload to transmit.
- * @param buf_len number of bytes in @a buf
- * @return #GNUNET_OK if everything goes well,
- * #GNUNET_SYSERR in case of an error.
- */
-int
-GCCH_handle_local_data (struct CadetChannel *ch,
- struct GNUNET_CADET_ClientChannelNumber sender_ccn,
- const char *buf,
- size_t buf_len);
-
-
-/**
- * Handle ACK from client on local channel.
- *
- * @param ch channel to destroy
- * @param client_ccn ccn of the client sending the ack
- */
-void
-GCCH_handle_local_ack (struct CadetChannel *ch,
- struct GNUNET_CADET_ClientChannelNumber client_ccn);
-
-#endif
diff --git a/src/cadet/gnunet-service-cadet-new_connection.c b/src/cadet/gnunet-service-cadet-new_connection.c
deleted file mode 100644
index 6976e66e4a..0000000000
--- a/src/cadet/gnunet-service-cadet-new_connection.c
+++ /dev/null
@@ -1,1093 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2001-2017 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new_connection.c
- * @brief management of CORE-level end-to-end connections; establishes
- * end-to-end routes and transmits messages along the route
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_channel.h"
-#include "gnunet-service-cadet-new_connection.h"
-#include "gnunet-service-cadet-new_paths.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_tunnels.h"
-#include "gnunet_cadet_service.h"
-#include "gnunet_statistics_service.h"
-#include "cadet_protocol.h"
-
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-con",__VA_ARGS__)
-
-
-/**
- * All the states a connection can be in.
- */
-enum CadetConnectionState
-{
- /**
- * Uninitialized status, we have not yet even gotten the message queue.
- */
- CADET_CONNECTION_NEW,
-
- /**
- * Connection create message in queue, awaiting transmission by CORE.
- */
- CADET_CONNECTION_SENDING_CREATE,
-
- /**
- * Connection create message sent, waiting for ACK.
- */
- CADET_CONNECTION_SENT,
-
- /**
- * We are an inbound connection, and received a CREATE. Need to
- * send an CREATE_ACK back.
- */
- CADET_CONNECTION_CREATE_RECEIVED,
-
- /**
- * Connection confirmed, ready to carry traffic.
- */
- CADET_CONNECTION_READY
-
-};
-
-
-/**
- * Low-level connection to a destination.
- */
-struct CadetConnection
-{
-
- /**
- * ID of the connection.
- */
- struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
-
- /**
- * To which peer does this connection go?
- */
- struct CadetPeer *destination;
-
- /**
- * Which tunnel is using this connection?
- */
- struct CadetTConnection *ct;
-
- /**
- * Path we are using to our destination.
- */
- struct CadetPeerPath *path;
-
- /**
- * Pending message, NULL if we are ready to transmit.
- */
- struct GNUNET_MQ_Envelope *env;
-
- /**
- * Handle for calling #GCP_request_mq_cancel() once we are finished.
- */
- struct GCP_MessageQueueManager *mq_man;
-
- /**
- * Task for connection maintenance.
- */
- struct GNUNET_SCHEDULER_Task *task;
-
- /**
- * Queue entry for keepalive messages.
- */
- struct CadetTunnelQueueEntry *keepalive_qe;
-
- /**
- * Function to call once we are ready to transmit.
- */
- GCC_ReadyCallback ready_cb;
-
- /**
- * Closure for @e ready_cb.
- */
- void *ready_cb_cls;
-
- /**
- * How long do we wait before we try again with a CREATE message?
- */
- struct GNUNET_TIME_Relative retry_delay;
-
- /**
- * Performance metrics for this connection.
- */
- struct CadetConnectionMetrics metrics;
-
- /**
- * State of the connection.
- */
- enum CadetConnectionState state;
-
- /**
- * Options for the route, control buffering.
- */
- enum GNUNET_CADET_ChannelOption options;
-
- /**
- * How many latency observations did we make for this connection?
- */
- unsigned int latency_datapoints;
-
- /**
- * Offset of our @e destination in @e path.
- */
- unsigned int off;
-
- /**
- * Are we ready to transmit via @e mq_man right now?
- */
- int mqm_ready;
-
-};
-
-
-/**
- * Lookup a connection by its identifier.
- *
- * @param cid identifier to resolve
- * @return NULL if connection was not found
- */
-struct CadetConnection *
-GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
- return GNUNET_CONTAINER_multishortmap_get (connections,
- &cid->connection_of_tunnel);
-}
-
-
-/**
- * Update the connection state. Also triggers the necessary
- * MQM notifications.
- *
- * @param cc connection to update the state for
- * @param new_state new state for @a cc
- * @param new_mqm_ready new `mqm_ready` state for @a cc
- */
-static void
-update_state (struct CadetConnection *cc,
- enum CadetConnectionState new_state,
- int new_mqm_ready)
-{
- int old_ready;
- int new_ready;
-
- if ( (new_state == cc->state) &&
- (new_mqm_ready == cc->mqm_ready) )
- return; /* no change, nothing to do */
- old_ready = ( (CADET_CONNECTION_READY == cc->state) &&
- (GNUNET_YES == cc->mqm_ready) );
- new_ready = ( (CADET_CONNECTION_READY == new_state) &&
- (GNUNET_YES == new_mqm_ready) );
- cc->state = new_state;
- cc->mqm_ready = new_mqm_ready;
- if (old_ready != new_ready)
- cc->ready_cb (cc->ready_cb_cls,
- new_ready);
-}
-
-
-/**
- * Destroy a connection, part of the internal implementation. Called
- * only from #GCC_destroy_from_core() or #GCC_destroy_from_tunnel().
- *
- * @param cc connection to destroy
- */
-static void
-GCC_destroy (struct CadetConnection *cc)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Destroying %s\n",
- GCC_2s (cc));
- if (NULL != cc->mq_man)
- {
- GCP_request_mq_cancel (cc->mq_man,
- NULL);
- cc->mq_man = NULL;
- }
- if (NULL != cc->task)
- {
- GNUNET_SCHEDULER_cancel (cc->task);
- cc->task = NULL;
- }
- if (NULL != cc->keepalive_qe)
- {
- GCT_send_cancel (cc->keepalive_qe);
- cc->keepalive_qe = NULL;
- }
- GCPP_del_connection (cc->path,
- cc->off,
- cc);
- for (unsigned int i=0;i<cc->off;i++)
- GCP_remove_connection (GCPP_get_peer_at_offset (cc->path,
- i),
- cc);
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multishortmap_remove (connections,
- &GCC_get_id (cc)->connection_of_tunnel,
- cc));
- GNUNET_free (cc);
-}
-
-
-
-/**
- * Destroy a connection, called when the CORE layer is already done
- * (i.e. has received a BROKEN message), but if we still have to
- * communicate the destruction of the connection to the tunnel (if one
- * exists).
- *
- * @param cc connection to destroy
- */
-void
-GCC_destroy_without_core (struct CadetConnection *cc)
-{
- if (NULL != cc->ct)
- {
- GCT_connection_lost (cc->ct);
- cc->ct = NULL;
- }
- GCC_destroy (cc);
-}
-
-
-/**
- * Destroy a connection, called if the tunnel association with the
- * connection was already broken, but we still need to notify the CORE
- * layer about the breakage.
- *
- * @param cc connection to destroy
- */
-void
-GCC_destroy_without_tunnel (struct CadetConnection *cc)
-{
- cc->ct = NULL;
- if ( (CADET_CONNECTION_SENDING_CREATE != cc->state) &&
- (NULL != cc->mq_man) )
- {
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_CADET_ConnectionDestroyMessage *destroy_msg;
-
- /* Need to notify next hop that we are down. */
- env = GNUNET_MQ_msg (destroy_msg,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);
- destroy_msg->cid = cc->cid;
- GCP_request_mq_cancel (cc->mq_man,
- env);
- cc->mq_man = NULL;
- }
- GCC_destroy (cc);
-}
-
-
-/**
- * Return the tunnel associated with this connection.
- *
- * @param cc connection to query
- * @return corresponding entry in the tunnel's connection list
- */
-struct CadetTConnection *
-GCC_get_ct (struct CadetConnection *cc)
-{
- return cc->ct;
-}
-
-
-/**
- * Obtain performance @a metrics from @a cc.
- *
- * @param cc connection to query
- * @return the metrics
- */
-const struct CadetConnectionMetrics *
-GCC_get_metrics (struct CadetConnection *cc)
-{
- return &cc->metrics;
-}
-
-
-/**
- * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the
- * tunnel to prevent it from timing out.
- *
- * @param cls the `struct CadetConnection` to keep alive.
- */
-static void
-send_keepalive (void *cls);
-
-
-/**
- * Keepalive was transmitted. Remember this, and possibly
- * schedule the next one.
- *
- * @param cls the `struct CadetConnection` to keep alive.
- * @param cid identifier of the connection within the tunnel, NULL
- * if transmission failed
- */
-static void
-keepalive_done (void *cls,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
- struct CadetConnection *cc = cls;
-
- cc->keepalive_qe = NULL;
- if ( (GNUNET_YES == cc->mqm_ready) &&
- (NULL == cc->task) )
- cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
- &send_keepalive,
- cc);
-}
-
-
-/**
- * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the
- * tunnel to prevent it from timing out.
- *
- * @param cls the `struct CadetConnection` to keep alive.
- */
-static void
-send_keepalive (void *cls)
-{
- struct CadetConnection *cc = cls;
- struct GNUNET_MessageHeader msg;
-
- cc->task = NULL;
- if (CADET_TUNNEL_KEY_OK != GCT_get_estate (cc->ct->t))
- {
- /* Tunnel not yet ready, wait with keepalives... */
- cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
- &send_keepalive,
- cc);
- return;
- }
- GNUNET_assert (NULL != cc->ct);
- GNUNET_assert (GNUNET_YES == cc->mqm_ready);
- GNUNET_assert (NULL == cc->keepalive_qe);
- LOG (GNUNET_ERROR_TYPE_INFO,
- "Sending KEEPALIVE on behalf of %s via %s\n",
- GCC_2s (cc),
- GCT_2s (cc->ct->t));
- GNUNET_STATISTICS_update (stats,
- "# keepalives sent",
- 1,
- GNUNET_NO);
- msg.size = htons (sizeof (msg));
- msg.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE);
-
- cc->keepalive_qe
- = GCT_send (cc->ct->t,
- &msg,
- &keepalive_done,
- cc);
-}
-
-
-/**
- * We sent a message for which we expect to receive an ACK via
- * the connection identified by @a cti.
- *
- * @param cid connection identifier where we expect an ACK
- */
-void
-GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
- struct CadetConnection *cc;
-
- cc = GCC_lookup (cid);
- if (NULL == cc)
- return; /* whopise, connection alredy down? */
- cc->metrics.num_acked_transmissions++;
-}
-
-
-/**
- * We observed an ACK for a message that was originally sent via
- * the connection identified by @a cti.
- *
- * @param cti connection identifier where we got an ACK for a message
- * that was originally sent via this connection (the ACK
- * may have gotten back to us via a different connection).
- */
-void
-GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
- struct CadetConnection *cc;
-
- cc = GCC_lookup (cid);
- if (NULL == cc)
- return; /* whopise, connection alredy down? */
- cc->metrics.num_successes++;
-}
-
-
-/**
- * We observed some the given @a latency on the connection
- * identified by @a cti. (The same connection was taken
- * in both directions.)
- *
- * @param cid connection identifier where we measured latency
- * @param latency the observed latency
- */
-void
-GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
- struct GNUNET_TIME_Relative latency)
-{
- struct CadetConnection *cc;
- double weight;
- double result;
-
- cc = GCC_lookup (cid);
- if (NULL == cc)
- return; /* whopise, connection alredy down? */
- GNUNET_STATISTICS_update (stats,
- "# latencies observed",
- 1,
- GNUNET_NO);
- cc->latency_datapoints++;
- if (cc->latency_datapoints >= 7)
- weight = 7.0;
- else
- weight = cc->latency_datapoints;
- /* Compute weighted average, giving at MOST weight 7 to the
- existing values, or less if that value is based on fewer than 7
- measurements. */
- result = (weight * cc->metrics.aged_latency.rel_value_us) + 1.0 * latency.rel_value_us;
- result /= (weight + 1.0);
- cc->metrics.aged_latency.rel_value_us = (uint64_t) result;
-}
-
-
-/**
- * A #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK was received for this connection, implying
- * that the end-to-end connection is up. Process it.
- *
- * @param cc the connection that got the ACK.
- */
-void
-GCC_handle_connection_create_ack (struct CadetConnection *cc)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Received CADET_CONNECTION_CREATE_ACK for %s in state %d (%s)\n",
- GCC_2s (cc),
- cc->state,
- (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy");
- if (CADET_CONNECTION_READY == cc->state)
- return; /* Duplicate ACK, ignore */
- if (NULL != cc->task)
- {
- GNUNET_SCHEDULER_cancel (cc->task);
- cc->task = NULL;
- }
- cc->metrics.age = GNUNET_TIME_absolute_get ();
- update_state (cc,
- CADET_CONNECTION_READY,
- cc->mqm_ready);
- if ( (NULL == cc->keepalive_qe) &&
- (GNUNET_YES == cc->mqm_ready) &&
- (NULL == cc->task) )
- cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
- &send_keepalive,
- cc);
-}
-
-
-/**
- * Handle KX message.
- *
- * @param cc connection that received encrypted message
- * @param msg the key exchange message
- */
-void
-GCC_handle_kx (struct CadetConnection *cc,
- const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
-{
- if (CADET_CONNECTION_SENT == cc->state)
- {
- /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine,
- clearly something is working, so pretend we got an ACK. */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n",
- GCC_2s (cc));
- GCC_handle_connection_create_ack (cc);
- }
- GCT_handle_kx (cc->ct,
- msg);
-}
-
-
-/**
- * Handle KX_AUTH message.
- *
- * @param cc connection that received encrypted message
- * @param msg the key exchange message
- */
-void
-GCC_handle_kx_auth (struct CadetConnection *cc,
- const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg)
-{
- if (CADET_CONNECTION_SENT == cc->state)
- {
- /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine,
- clearly something is working, so pretend we got an ACK. */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n",
- GCC_2s (cc));
- GCC_handle_connection_create_ack (cc);
- }
- GCT_handle_kx_auth (cc->ct,
- msg);
-}
-
-
-/**
- * Handle encrypted message.
- *
- * @param cc connection that received encrypted message
- * @param msg the encrypted message to decrypt
- */
-void
-GCC_handle_encrypted (struct CadetConnection *cc,
- const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
-{
- if (CADET_CONNECTION_SENT == cc->state)
- {
- /* We didn't get the CREATE_ACK, but instead got payload. That's fine,
- clearly something is working, so pretend we got an ACK. */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Faking connection ACK for %s due to ENCRYPTED payload\n",
- GCC_2s (cc));
- GCC_handle_connection_create_ack (cc);
- }
- cc->metrics.last_use = GNUNET_TIME_absolute_get ();
- GCT_handle_encrypted (cc->ct,
- msg);
-}
-
-
-/**
- * Send a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE message to the
- * first hop.
- *
- * @param cls the `struct CadetConnection` to initiate
- */
-static void
-send_create (void *cls)
-{
- struct CadetConnection *cc = cls;
- struct GNUNET_CADET_ConnectionCreateMessage *create_msg;
- struct GNUNET_PeerIdentity *pids;
- struct GNUNET_MQ_Envelope *env;
- unsigned int path_length;
-
- cc->task = NULL;
- GNUNET_assert (GNUNET_YES == cc->mqm_ready);
- path_length = GCPP_get_length (cc->path);
- env = GNUNET_MQ_msg_extra (create_msg,
- (1 + path_length) * sizeof (struct GNUNET_PeerIdentity),
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE);
- create_msg->options = htonl ((uint32_t) cc->options);
- create_msg->cid = cc->cid;
- pids = (struct GNUNET_PeerIdentity *) &create_msg[1];
- pids[0] = my_full_id;
- for (unsigned int i=0;i<path_length;i++)
- pids[i + 1] = *GCP_get_id (GCPP_get_peer_at_offset (cc->path,
- i));
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sending CADET_CONNECTION_CREATE message for %s\n",
- GCC_2s (cc));
- cc->env = env;
- update_state (cc,
- CADET_CONNECTION_SENT,
- GNUNET_NO);
- GCP_send (cc->mq_man,
- env);
-}
-
-
-/**
- * Send a CREATE_ACK message towards the origin.
- *
- * @param cls the `struct CadetConnection` to initiate
- */
-static void
-send_create_ack (void *cls)
-{
- struct CadetConnection *cc = cls;
- struct GNUNET_CADET_ConnectionCreateAckMessage *ack_msg;
- struct GNUNET_MQ_Envelope *env;
-
- cc->task = NULL;
- GNUNET_assert (CADET_CONNECTION_CREATE_RECEIVED == cc->state);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sending CONNECTION_CREATE_ACK message for %s\n",
- GCC_2s (cc));
- GNUNET_assert (GNUNET_YES == cc->mqm_ready);
- env = GNUNET_MQ_msg (ack_msg,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK);
- ack_msg->cid = cc->cid;
- cc->env = env;
- update_state (cc,
- CADET_CONNECTION_READY,
- GNUNET_NO);
- GCP_send (cc->mq_man,
- env);
-}
-
-
-/**
- * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a
- * connection that we already have. Either our ACK got lost
- * or something is fishy. Consider retransmitting the ACK.
- *
- * @param cc connection that got the duplicate CREATE
- */
-void
-GCC_handle_duplicate_create (struct CadetConnection *cc)
-{
- if (GNUNET_YES == cc->mqm_ready)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Got duplicate CREATE for %s, scheduling another ACK (%s)\n",
- GCC_2s (cc),
- (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy");
- /* Revert back to the state of having only received the 'CREATE',
- and immediately proceed to send the CREATE_ACK. */
- update_state (cc,
- CADET_CONNECTION_CREATE_RECEIVED,
- cc->mqm_ready);
- if (NULL != cc->task)
- GNUNET_SCHEDULER_cancel (cc->task);
- cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack,
- cc);
- }
- else
- {
- /* We are currently sending something else back, which
- can only be an ACK or payload, either of which would
- do. So actually no need to do anything. */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Got duplicate CREATE for %s. MQ is busy, not queueing another ACK\n",
- GCC_2s (cc));
- }
-}
-
-
-/**
- * There has been a change in the message queue existence for our
- * peer at the first hop. Adjust accordingly.
- *
- * @param cls the `struct CadetConnection`
- * @param available #GNUNET_YES if sending is now possible,
- * #GNUNET_NO if sending is no longer possible
- * #GNUNET_SYSERR if sending is no longer possible
- * and the last envelope was discarded
- */
-static void
-manage_first_hop_mq (void *cls,
- int available)
-{
- struct CadetConnection *cc = cls;
-
- if (GNUNET_YES != available)
- {
- /* Connection is down, for now... */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Core MQ for %s went down\n",
- GCC_2s (cc));
- update_state (cc,
- CADET_CONNECTION_NEW,
- GNUNET_NO);
- cc->retry_delay = GNUNET_TIME_UNIT_ZERO;
- if (NULL != cc->task)
- {
- GNUNET_SCHEDULER_cancel (cc->task);
- cc->task = NULL;
- }
- return;
- }
-
- update_state (cc,
- cc->state,
- GNUNET_YES);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Core MQ for %s became available in state %d\n",
- GCC_2s (cc),
- cc->state);
- switch (cc->state)
- {
- case CADET_CONNECTION_NEW:
- /* Transmit immediately */
- cc->task = GNUNET_SCHEDULER_add_now (&send_create,
- cc);
- break;
- case CADET_CONNECTION_SENDING_CREATE:
- /* Should not be possible to be called in this state. */
- GNUNET_assert (0);
- break;
- case CADET_CONNECTION_SENT:
- /* Retry a bit later... */
- cc->retry_delay = GNUNET_TIME_STD_BACKOFF (cc->retry_delay);
- cc->task = GNUNET_SCHEDULER_add_delayed (cc->retry_delay,
- &send_create,
- cc);
- break;
- case CADET_CONNECTION_CREATE_RECEIVED:
- /* We got the 'CREATE' (incoming connection), should send the CREATE_ACK */
- cc->metrics.age = GNUNET_TIME_absolute_get ();
- cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack,
- cc);
- break;
- case CADET_CONNECTION_READY:
- if ( (NULL == cc->keepalive_qe) &&
- (GNUNET_YES == cc->mqm_ready) &&
- (NULL == cc->task) )
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Scheduling keepalive for %s in %s\n",
- GCC_2s (cc),
- GNUNET_STRINGS_relative_time_to_string (keepalive_period,
- GNUNET_YES));
- cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
- &send_keepalive,
- cc);
- }
- break;
- }
-}
-
-
-/**
- * Create a connection to @a destination via @a path and notify @a cb
- * whenever we are ready for more data. Shared logic independent of
- * who is initiating the connection.
- *
- * @param destination where to go
- * @param path which path to take (may not be the full path)
- * @param off offset of @a destination on @a path
- * @param options options for the connection
- * @param ct which tunnel uses this connection
- * @param init_state initial state for the connection
- * @param ready_cb function to call when ready to transmit
- * @param ready_cb_cls closure for @a cb
- * @return handle to the connection
- */
-static struct CadetConnection *
-connection_create (struct CadetPeer *destination,
- struct CadetPeerPath *path,
- unsigned int off,
- enum GNUNET_CADET_ChannelOption options,
- struct CadetTConnection *ct,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
- enum CadetConnectionState init_state,
- GCC_ReadyCallback ready_cb,
- void *ready_cb_cls)
-{
- struct CadetConnection *cc;
- struct CadetPeer *first_hop;
-
- cc = GNUNET_new (struct CadetConnection);
- cc->options = options;
- cc->state = init_state;
- cc->ct = ct;
- cc->cid = *cid;
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CONTAINER_multishortmap_put (connections,
- &GCC_get_id (cc)->connection_of_tunnel,
- cc,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
- cc->ready_cb = ready_cb;
- cc->ready_cb_cls = ready_cb_cls;
- cc->path = path;
- cc->off = off;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Creating %s using path %s\n",
- GCC_2s (cc),
- GCPP_2s (path));
- GCPP_add_connection (path,
- off,
- cc);
- for (unsigned int i=0;i<off;i++)
- GCP_add_connection (GCPP_get_peer_at_offset (path,
- i),
- cc);
-
- first_hop = GCPP_get_peer_at_offset (path,
- 0);
- cc->mq_man = GCP_request_mq (first_hop,
- &manage_first_hop_mq,
- cc);
- return cc;
-}
-
-
-/**
- * Create a connection to @a destination via @a path and
- * notify @a cb whenever we are ready for more data. This
- * is an inbound tunnel, so we must use the existing @a cid
- *
- * @param destination where to go
- * @param path which path to take (may not be the full path)
- * @param options options for the connection
- * @param ct which tunnel uses this connection
- * @param ready_cb function to call when ready to transmit
- * @param ready_cb_cls closure for @a cb
- * @return handle to the connection, NULL if we already have
- * a connection that takes precedence on @a path
- */
-struct CadetConnection *
-GCC_create_inbound (struct CadetPeer *destination,
- struct CadetPeerPath *path,
- enum GNUNET_CADET_ChannelOption options,
- struct CadetTConnection *ct,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
- GCC_ReadyCallback ready_cb,
- void *ready_cb_cls)
-{
- struct CadetConnection *cc;
- unsigned int off;
-
- off = GCPP_find_peer (path,
- destination);
- GNUNET_assert (UINT_MAX != off);
- cc = GCPP_get_connection (path,
- destination,
- off);
- if (NULL != cc)
- {
- int cmp;
-
- cmp = memcmp (cid,
- &cc->cid,
- sizeof (*cid));
- if (0 == cmp)
- {
- /* Two peers picked the SAME random connection identifier at the
- same time for the same path? Must be malicious. Drop
- connection (existing and inbound), even if it is the only
- one. */
- GNUNET_break_op (0);
- GCT_connection_lost (cc->ct);
- GCC_destroy_without_tunnel (cc);
- return NULL;
- }
- if (0 < cmp)
- {
- /* drop existing */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Got two connections on %s, dropping my existing %s\n",
- GCPP_2s (path),
- GCC_2s (cc));
- GCT_connection_lost (cc->ct);
- GCC_destroy_without_tunnel (cc);
- }
- else
- {
- /* keep existing */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Got two connections on %s, keeping my existing %s\n",
- GCPP_2s (path),
- GCC_2s (cc));
- return NULL;
- }
- }
-
- return connection_create (destination,
- path,
- off,
- options,
- ct,
- cid,
- CADET_CONNECTION_CREATE_RECEIVED,
- ready_cb,
- ready_cb_cls);
-}
-
-
-/**
- * Create a connection to @a destination via @a path and
- * notify @a cb whenever we are ready for more data.
- *
- * @param destination where to go
- * @param path which path to take (may not be the full path)
- * @param off offset of @a destination on @a path
- * @param options options for the connection
- * @param ct tunnel that uses the connection
- * @param ready_cb function to call when ready to transmit
- * @param ready_cb_cls closure for @a cb
- * @return handle to the connection
- */
-struct CadetConnection *
-GCC_create (struct CadetPeer *destination,
- struct CadetPeerPath *path,
- unsigned int off,
- enum GNUNET_CADET_ChannelOption options,
- struct CadetTConnection *ct,
- GCC_ReadyCallback ready_cb,
- void *ready_cb_cls)
-{
- struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
-
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
- &cid,
- sizeof (cid));
- return connection_create (destination,
- path,
- off,
- options,
- ct,
- &cid,
- CADET_CONNECTION_NEW,
- ready_cb,
- ready_cb_cls);
-}
-
-
-/**
- * Transmit message @a msg via connection @a cc. Must only be called
- * (once) after the connection has signalled that it is ready via the
- * `ready_cb`. Clients can also use #GCC_is_ready() to check if the
- * connection is right now ready for transmission.
- *
- * @param cc connection identification
- * @param env envelope with message to transmit; must NOT
- * yet have a #GNUNET_MQ_notify_sent() callback attached to it
- */
-void
-GCC_transmit (struct CadetConnection *cc,
- struct GNUNET_MQ_Envelope *env)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Scheduling message for transmission on %s\n",
- GCC_2s (cc));
- GNUNET_assert (GNUNET_YES == cc->mqm_ready);
- GNUNET_assert (CADET_CONNECTION_READY == cc->state);
- cc->metrics.last_use = GNUNET_TIME_absolute_get ();
- cc->mqm_ready = GNUNET_NO;
- if (NULL != cc->task)
- {
- GNUNET_SCHEDULER_cancel (cc->task);
- cc->task = NULL;
- }
- GCP_send (cc->mq_man,
- env);
-}
-
-
-/**
- * Obtain the path used by this connection.
- *
- * @param cc connection
- * @return path to @a cc
- */
-struct CadetPeerPath *
-GCC_get_path (struct CadetConnection *cc)
-{
- return cc->path;
-}
-
-
-/**
- * Obtain unique ID for the connection.
- *
- * @param cc connection.
- * @return unique number of the connection
- */
-const struct GNUNET_CADET_ConnectionTunnelIdentifier *
-GCC_get_id (struct CadetConnection *cc)
-{
- return &cc->cid;
-}
-
-
-/**
- * Get a (static) string for a connection.
- *
- * @param cc Connection.
- */
-const char *
-GCC_2s (const struct CadetConnection *cc)
-{
- static char buf[128];
-
- if (NULL == cc)
- return "Connection(NULL)";
-
- if (NULL != cc->ct)
- {
- GNUNET_snprintf (buf,
- sizeof (buf),
- "Connection %s (%s)",
- GNUNET_sh2s (&cc->cid.connection_of_tunnel),
- GCT_2s (cc->ct->t));
- return buf;
- }
- GNUNET_snprintf (buf,
- sizeof (buf),
- "Connection %s",
- GNUNET_sh2s (&cc->cid.connection_of_tunnel));
- return buf;
-}
-
-
-#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-con",__VA_ARGS__)
-
-
-/**
- * Log connection info.
- *
- * @param cc connection
- * @param level Debug level to use.
- */
-void
-GCC_debug (struct CadetConnection *cc,
- enum GNUNET_ErrorType level)
-{
- int do_log;
-
- do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
- "cadet-con",
- __FILE__, __FUNCTION__, __LINE__);
- if (0 == do_log)
- return;
- if (NULL == cc)
- {
- LOG2 (level,
- "Connection (NULL)\n");
- return;
- }
- LOG2 (level,
- "%s to %s via path %s in state %d is %s\n",
- GCC_2s (cc),
- GCP_2s (cc->destination),
- GCPP_2s (cc->path),
- cc->state,
- (GNUNET_YES == cc->mqm_ready) ? "ready" : "busy");
-}
-
-/* end of gnunet-service-cadet-new_connection.c */
diff --git a/src/cadet/gnunet-service-cadet-new_connection.h b/src/cadet/gnunet-service-cadet-new_connection.h
deleted file mode 100644
index e48b208fda..0000000000
--- a/src/cadet/gnunet-service-cadet-new_connection.h
+++ /dev/null
@@ -1,339 +0,0 @@
-
-/*
- This file is part of GNUnet.
- Copyright (C) 2001-2017 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new_connection.h
- * @brief A connection is a live end-to-end messaging mechanism
- * where the peers are identified by a path and know how
- * to forward along the route using a connection identifier
- * for routing the data.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#ifndef GNUNET_SERVICE_CADET_CONNECTION_H
-#define GNUNET_SERVICE_CADET_CONNECTION_H
-
-#include "gnunet_util_lib.h"
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "cadet_protocol.h"
-
-
-/**
- * Function called to notify tunnel about change in our readyness.
- *
- * @param cls closure
- * @param is_ready #GNUNET_YES if the connection is now ready for transmission,
- * #GNUNET_NO if the connection is no longer ready for transmission
- */
-typedef void
-(*GCC_ReadyCallback)(void *cls,
- int is_ready);
-
-
-/**
- * Destroy a connection, called when the CORE layer is already done
- * (i.e. has received a BROKEN message), but if we still have to
- * communicate the destruction of the connection to the tunnel (if one
- * exists).
- *
- * @param cc connection to destroy
- */
-void
-GCC_destroy_without_core (struct CadetConnection *cc);
-
-
-/**
- * Destroy a connection, called if the tunnel association with the
- * connection was already broken, but we still need to notify the CORE
- * layer about the breakage.
- *
- * @param cc connection to destroy
- */
-void
-GCC_destroy_without_tunnel (struct CadetConnection *cc);
-
-
-/**
- * Lookup a connection by its identifier.
- *
- * @param cid identifier to resolve
- * @return NULL if connection was not found
- */
-struct CadetConnection *
-GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
-
-
-/**
- * Create a connection to @a destination via @a path and
- * notify @a cb whenever we are ready for more data.
- *
- * @param destination where to go
- * @param path which path to take (may not be the full path)
- * @param off offset of @a destination on @a path
- * @param options options for the connection
- * @param ct which tunnel uses this connection
- * @param ready_cb function to call when ready to transmit
- * @param ready_cb_cls closure for @a cb
- * @return handle to the connection
- */
-struct CadetConnection *
-GCC_create (struct CadetPeer *destination,
- struct CadetPeerPath *path,
- unsigned int off,
- enum GNUNET_CADET_ChannelOption options,
- struct CadetTConnection *ct,
- GCC_ReadyCallback ready_cb,
- void *ready_cb_cls);
-
-
-/**
- * Create a connection to @a destination via @a path and
- * notify @a cb whenever we are ready for more data. This
- * is an inbound tunnel, so we must use the existing @a cid
- *
- * @param destination where to go
- * @param path which path to take (may not be the full path)
- * @param options options for the connection
- * @param ct which tunnel uses this connection
- * @param ready_cb function to call when ready to transmit
- * @param ready_cb_cls closure for @a cb
- * @return handle to the connection, NULL if we already have
- * a connection that takes precedence on @a path
- */
-struct CadetConnection *
-GCC_create_inbound (struct CadetPeer *destination,
- struct CadetPeerPath *path,
- enum GNUNET_CADET_ChannelOption options,
- struct CadetTConnection *ct,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
- GCC_ReadyCallback ready_cb,
- void *ready_cb_cls);
-
-
-/**
- * Transmit message @a msg via connection @a cc. Must only be called
- * (once) after the connection has signalled that it is ready via the
- * `ready_cb`. Clients can also use #GCC_is_ready() to check if the
- * connection is right now ready for transmission.
- *
- * @param cc connection identification
- * @param env envelope with message to transmit;
- * the #GNUNET_MQ_notify_send() must not have yet been used
- * for the envelope. Also, the message better match the
- * connection identifier of this connection...
- */
-void
-GCC_transmit (struct CadetConnection *cc,
- struct GNUNET_MQ_Envelope *env);
-
-
-/**
- * A CREATE_ACK was received for this connection, process it.
- *
- * @param cc the connection that got the ACK.
- */
-void
-GCC_handle_connection_create_ack (struct CadetConnection *cc);
-
-
-/**
- * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a
- * connection that we already have. Either our ACK got lost
- * or something is fishy. Consider retransmitting the ACK.
- *
- * @param cc connection that got the duplicate CREATE
- */
-void
-GCC_handle_duplicate_create (struct CadetConnection *cc);
-
-
-/**
- * Handle KX message.
- *
- * @param cc connection that received encrypted message
- * @param msg the key exchange message
- */
-void
-GCC_handle_kx (struct CadetConnection *cc,
- const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg);
-
-
-/**
- * Handle KX_AUTH message.
- *
- * @param cc connection that received encrypted message
- * @param msg the key exchange message
- */
-void
-GCC_handle_kx_auth (struct CadetConnection *cc,
- const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg);
-
-
-/**
- * Performance metrics for a connection.
- */
-struct CadetConnectionMetrics
-{
-
- /**
- * Our current best estimate of the latency, based on a weighted
- * average of at least @a latency_datapoints values.
- */
- struct GNUNET_TIME_Relative aged_latency;
-
- /**
- * When was this connection first established? (by us sending or
- * receiving the CREATE_ACK for the first time)
- */
- struct GNUNET_TIME_Absolute age;
-
- /**
- * When was this connection last used? (by us sending or
- * receiving a PAYLOAD message on it)
- */
- struct GNUNET_TIME_Absolute last_use;
-
- /**
- * How many packets that ought to generate an ACK did we send via
- * this connection?
- */
- unsigned long long num_acked_transmissions;
-
- /**
- * Number of packets that were sent via this connection did actually
- * receive an ACK? (Note: ACKs may be transmitted and lost via
- * other connections, so this value should only be interpreted
- * relative to @e num_acked_transmissions and in relation to other
- * connections.)
- */
- unsigned long long num_successes;
-
-};
-
-
-/**
- * Obtain performance @a metrics from @a cc.
- *
- * @param cc connection to query
- * @return the metrics
- */
-const struct CadetConnectionMetrics *
-GCC_get_metrics (struct CadetConnection *cc);
-
-
-/**
- * Handle encrypted message.
- *
- * @param cc connection that received encrypted message
- * @param msg the encrypted message to decrypt
- */
-void
-GCC_handle_encrypted (struct CadetConnection *cc,
- const struct GNUNET_CADET_TunnelEncryptedMessage *msg);
-
-
-/**
- * We sent a message for which we expect to receive an ACK via
- * the connection identified by @a cti.
- *
- * @param cid connection identifier where we expect an ACK
- */
-void
-GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
-
-
-/**
- * We observed an ACK for a message that was originally sent via
- * the connection identified by @a cti.
- *
- * @param cid connection identifier where we got an ACK for a message
- * that was originally sent via this connection (the ACK
- * may have gotten back to us via a different connection).
- */
-void
-GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
-
-
-/**
- * We observed some the given @a latency on the connection
- * identified by @a cti. (The same connection was taken
- * in both directions.)
- *
- * @param cti connection identifier where we measured latency
- * @param latency the observed latency
- */
-void
-GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
- struct GNUNET_TIME_Relative latency);
-
-
-/**
- * Return the tunnel associated with this connection.
- *
- * @param cc connection to query
- * @return corresponding entry in the tunnel's connection list
- */
-struct CadetTConnection *
-GCC_get_ct (struct CadetConnection *cc);
-
-
-/**
- * Obtain the path used by this connection.
- *
- * @param cc connection
- * @return path to @a cc
- */
-struct CadetPeerPath *
-GCC_get_path (struct CadetConnection *cc);
-
-
-/**
- * Obtain unique ID for the connection.
- *
- * @param cc connection.
- * @return unique number of the connection
- */
-const struct GNUNET_CADET_ConnectionTunnelIdentifier *
-GCC_get_id (struct CadetConnection *cc);
-
-
-/**
- * Get a (static) string for a connection.
- *
- * @param cc Connection.
- */
-const char *
-GCC_2s (const struct CadetConnection *cc);
-
-
-/**
- * Log connection info.
- *
- * @param cc connection
- * @param level Debug level to use.
- */
-void
-GCC_debug (struct CadetConnection *cc,
- enum GNUNET_ErrorType level);
-
-
-#endif
diff --git a/src/cadet/gnunet-service-cadet-new_dht.c b/src/cadet/gnunet-service-cadet-new_dht.c
deleted file mode 100644
index 849562f237..0000000000
--- a/src/cadet/gnunet-service-cadet-new_dht.c
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2013, 2017 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/gnunet-service-cadet-new_dht.c
- * @brief Information we track per peer.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_dht_service.h"
-#include "gnunet_statistics_service.h"
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_dht.h"
-#include "gnunet-service-cadet-new_hello.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_paths.h"
-
-/**
- * How long do we wait before first announcing our presence to the DHT.
- * Used to wait for our HELLO to be available. Note that we also get
- * notifications when our HELLO is ready, so this is just the maximum
- * we wait for the first notification.
- */
-#define STARTUP_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500)
-
-/**
- * How long do we wait after we get an updated HELLO before publishing?
- * Allows for the HELLO to be updated again quickly, for example in
- * case multiple addresses changed and we got a partial update.
- */
-#define CHANGE_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)
-
-
-#define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__)
-
-
-/**
- * Handle for DHT searches.
- */
-struct GCD_search_handle
-{
- /**
- * DHT_GET handle.
- */
- struct GNUNET_DHT_GetHandle *dhtget;
-
-};
-
-
-/**
- * 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 struct GNUNET_SCHEDULER_Task *announce_id_task;
-
-/**
- * Delay for the next ID announce.
- */
-static struct GNUNET_TIME_Relative announce_delay;
-
-
-/**
- * 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 @a get_path
- * @param put_path path of the put request
- * @param put_path_length length of the @a 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)
-{
- const struct GNUNET_HELLO_Message *hello = data;
- struct CadetPeer *peer;
-
- GCPP_try_path_from_dht (get_path,
- get_path_length,
- put_path,
- put_path_length);
- if ( (size >= sizeof (struct GNUNET_HELLO_Message)) &&
- (ntohs (hello->header.size) == size) &&
- (size == GNUNET_HELLO_size (hello)) )
- {
- peer = GCP_get (&put_path[0],
- GNUNET_YES);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Got HELLO for %s\n",
- GCP_2s (peer));
- GCP_set_hello (peer,
- hello);
- }
-}
-
-
-/**
- * Periodically announce self id in the DHT
- *
- * @param cls closure
- */
-static void
-announce_id (void *cls)
-{
- struct GNUNET_HashCode phash;
- const struct GNUNET_HELLO_Message *hello;
- size_t size;
- struct GNUNET_TIME_Absolute expiration;
- struct GNUNET_TIME_Relative next_put;
-
- hello = GCH_get_mine ();
- size = (NULL != hello) ? GNUNET_HELLO_size (hello) : 0;
- if (0 == size)
- {
- expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
- announce_delay);
- announce_delay = GNUNET_TIME_STD_BACKOFF (announce_delay);
- }
- else
- {
- expiration = GNUNET_HELLO_get_last_expiration (hello);
- announce_delay = GNUNET_TIME_UNIT_SECONDS;
- }
-
- /* Call again in id_announce_time, unless HELLO expires first,
- * but wait at least 1s. */
- next_put
- = GNUNET_TIME_absolute_get_remaining (expiration);
- next_put
- = GNUNET_TIME_relative_min (next_put,
- id_announce_time);
- next_put
- = GNUNET_TIME_relative_max (next_put,
- GNUNET_TIME_UNIT_SECONDS);
- announce_id_task
- = GNUNET_SCHEDULER_add_delayed (next_put,
- &announce_id,
- cls);
- GNUNET_STATISTICS_update (stats,
- "# DHT announce",
- 1,
- GNUNET_NO);
- memset (&phash,
- 0,
- sizeof (phash));
- GNUNET_memcpy (&phash,
- &my_full_id,
- sizeof (my_full_id));
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Announcing my HELLO (%u bytes) in the DHT\n",
- size);
- 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 */
- NULL, /* Continuation */
- NULL); /* Continuation closure */
-}
-
-
-/**
- * Function called by the HELLO subsystem whenever OUR hello
- * changes. Re-triggers the DHT PUT immediately.
- */
-void
-GCD_hello_update ()
-{
- if (NULL == announce_id_task)
- return; /* too early */
- GNUNET_SCHEDULER_cancel (announce_id_task);
- announce_id_task
- = GNUNET_SCHEDULER_add_delayed (CHANGE_DELAY,
- &announce_id,
- NULL);
-}
-
-
-/**
- * Initialize the DHT subsystem.
- *
- * @param c Configuration.
- */
-void
-GCD_init (const struct GNUNET_CONFIGURATION_Handle *c)
-{
- 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);
- GNUNET_break (NULL != dht_handle);
- announce_delay = GNUNET_TIME_UNIT_SECONDS;
- announce_id_task = GNUNET_SCHEDULER_add_delayed (STARTUP_DELAY,
- &announce_id,
- NULL);
-}
-
-
-/**
- * Shut down the DHT subsystem.
- */
-void
-GCD_shutdown (void)
-{
- if (NULL != dht_handle)
- {
- GNUNET_DHT_disconnect (dht_handle);
- dht_handle = NULL;
- }
- if (NULL != announce_id_task)
- {
- GNUNET_SCHEDULER_cancel (announce_id_task);
- announce_id_task = NULL;
- }
-}
-
-
-/**
- * Search DHT for paths to @a peeR_id
- *
- * @param peer_id peer to search for
- * @return handle to abort search
- */
-struct GCD_search_handle *
-GCD_search (const struct GNUNET_PeerIdentity *peer_id)
-{
- struct GNUNET_HashCode phash;
- struct GCD_search_handle *h;
-
- GNUNET_STATISTICS_update (stats,
- "# DHT search",
- 1,
- GNUNET_NO);
- memset (&phash,
- 0,
- sizeof (phash));
- GNUNET_memcpy (&phash,
- peer_id,
- sizeof (*peer_id));
-
- h = GNUNET_new (struct GCD_search_handle);
- 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);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Starting DHT GET for peer %s (%p)\n",
- GNUNET_i2s (peer_id),
- h);
- return h;
-}
-
-
-/**
- * Stop DHT search started with #GCD_search().
- *
- * @param h handle to search to stop
- */
-void
-GCD_search_stop (struct GCD_search_handle *h)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Stopping DHT GET %p\n",
- h);
- GNUNET_DHT_get_stop (h->dhtget);
- GNUNET_free (h);
-}
-
-/* end of gnunet-service-cadet_dht.c */
diff --git a/src/cadet/gnunet-service-cadet-new_dht.h b/src/cadet/gnunet-service-cadet-new_dht.h
deleted file mode 100644
index 5d7ab29a06..0000000000
--- a/src/cadet/gnunet-service-cadet-new_dht.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2013, 2017 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_dht.h
- * @brief cadet service; dealing with DHT requests and results
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * All functions in this file should use the prefix GCD (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"
-
-/**
- * Handle for DHT search operation.
- */
-struct GCD_search_handle;
-
-
-/**
- * Initialize the DHT subsystem.
- *
- * @param c Configuration.
- */
-void
-GCD_init (const struct GNUNET_CONFIGURATION_Handle *c);
-
-
-/**
- * Shut down the DHT subsystem.
- */
-void
-GCD_shutdown (void);
-
-
-/**
- * Function called by the HELLO subsystem whenever OUR hello
- * changes. Re-triggers the DHT PUT immediately.
- */
-void
-GCD_hello_update (void);
-
-/**
- * Search DHT for paths to @a peeR_id
- *
- * @param peer_id peer to search for
- * @return handle to abort search
- */
-struct GCD_search_handle *
-GCD_search (const struct GNUNET_PeerIdentity *peer_id);
-
-
-/**
- * Stop DHT search started with #GCD_search().
- *
- * @param h handle to search to stop
- */
-void
-GCD_search_stop (struct GCD_search_handle *h);
-
-
-#if 0 /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_CADET_SERVICE_DHT_H */
-#endif
-/* end of gnunet-service-cadet_dht.h */
diff --git a/src/cadet/gnunet-service-cadet-new_hello.c b/src/cadet/gnunet-service-cadet-new_hello.c
deleted file mode 100644
index a24325adac..0000000000
--- a/src/cadet/gnunet-service-cadet-new_hello.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2014, 2017 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/gnunet-service-cadet-new_hello.c
- * @brief spread knowledge about how to contact other peers from PEERINFO
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * TODO:
- * - is most of this necessary/helpful?
- * - should we not simply restrict this to OUR hello?
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#include "gnunet_statistics_service.h"
-#include "gnunet_peerinfo_service.h"
-#include "cadet_protocol.h"
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_dht.h"
-#include "gnunet-service-cadet-new_hello.h"
-#include "gnunet-service-cadet-new_peer.h"
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-hll",__VA_ARGS__)
-
-/**
- * Hello message of local peer.
- */
-static struct GNUNET_HELLO_Message *mine;
-
-/**
- * Handle to peerinfo service.
- */
-static struct GNUNET_PEERINFO_Handle *peerinfo;
-
-/**
- * Iterator context.
- */
-static struct GNUNET_PEERINFO_NotifyContext *nc;
-
-
-/**
- * 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) )
- return;
- if (0 == memcmp (id,
- &my_full_id,
- sizeof (struct GNUNET_PeerIdentity)))
- {
- GNUNET_free_non_null (mine);
- mine = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (&hello->header);
- GCD_hello_update ();
- 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 = GCP_get (id,
- GNUNET_YES);
- GCP_set_hello (peer,
- hello);
-}
-
-
-/**
- * Initialize the hello subsystem.
- *
- * @param c Configuration.
- */
-void
-GCH_init (const struct GNUNET_CONFIGURATION_Handle *c)
-{
- 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
-GCH_shutdown ()
-{
- if (NULL != nc)
- {
- GNUNET_PEERINFO_notify_cancel (nc);
- nc = NULL;
- }
- if (NULL != peerinfo)
- {
- GNUNET_PEERINFO_disconnect (peerinfo);
- peerinfo = NULL;
- }
- if (NULL != mine)
- {
- GNUNET_free (mine);
- mine = NULL;
- }
-}
-
-
-/**
- * Get own hello message.
- *
- * @return Own hello message.
- */
-const struct GNUNET_HELLO_Message *
-GCH_get_mine (void)
-{
- return mine;
-}
-
-/* end of gnunet-service-cadet-new_hello.c */
diff --git a/src/cadet/gnunet-service-cadet-new_hello.h b/src/cadet/gnunet-service-cadet-new_hello.h
deleted file mode 100644
index 4291ae985d..0000000000
--- a/src/cadet/gnunet-service-cadet-new_hello.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2014, 2017 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_hello.h
- * @brief cadet service; dealing with hello messages
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * All functions in this file should use the prefix GCH (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
-GCH_init (const struct GNUNET_CONFIGURATION_Handle *c);
-
-
-/**
- * Shut down the hello subsystem.
- */
-void
-GCH_shutdown (void);
-
-
-/**
- * Get own hello message.
- *
- * @return Own hello message.
- */
-const struct GNUNET_HELLO_Message *
-GCH_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-new_peer.c b/src/cadet/gnunet-service-cadet-new_peer.c
deleted file mode 100644
index 29aef6895a..0000000000
--- a/src/cadet/gnunet-service-cadet-new_peer.c
+++ /dev/null
@@ -1,1478 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2001-2017 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new_peer.c
- * @brief Information we track per peer.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * TODO:
- * - optimize stopping/restarting DHT search to situations
- * where we actually need it (i.e. not if we have a direct connection,
- * or if we already have plenty of good short ones, or maybe even
- * to take a break if we have some connections and have searched a lot (?))
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_hello_lib.h"
-#include "gnunet_signatures.h"
-#include "gnunet_transport_service.h"
-#include "gnunet_ats_service.h"
-#include "gnunet_core_service.h"
-#include "gnunet_statistics_service.h"
-#include "cadet_protocol.h"
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_connection.h"
-#include "gnunet-service-cadet-new_dht.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_paths.h"
-#include "gnunet-service-cadet-new_tunnels.h"
-
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-per",__VA_ARGS__)
-
-
-/**
- * How long do we wait until tearing down an idle peer?
- */
-#define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
-
-/**
- * How long do we keep paths around if we no longer care about the peer?
- */
-#define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
-
-
-
-
-/**
- * Data structure used to track whom we have to notify about changes
- * to our message queue.
- */
-struct GCP_MessageQueueManager
-{
-
- /**
- * Kept in a DLL.
- */
- struct GCP_MessageQueueManager *next;
-
- /**
- * Kept in a DLL.
- */
- struct GCP_MessageQueueManager *prev;
-
- /**
- * Function to call with updated message queue object.
- */
- GCP_MessageQueueNotificationCallback cb;
-
- /**
- * Closure for @e cb.
- */
- void *cb_cls;
-
- /**
- * The peer this is for.
- */
- struct CadetPeer *cp;
-
- /**
- * Envelope this manager would like to transmit once it is its turn.
- */
- struct GNUNET_MQ_Envelope *env;
-
-};
-
-
-/**
- * Struct containing all information regarding a given peer
- */
-struct CadetPeer
-{
- /**
- * ID of the peer
- */
- struct GNUNET_PeerIdentity pid;
-
- /**
- * Last time we heard from this peer (currently not used!)
- */
- struct GNUNET_TIME_Absolute last_contactXXX;
-
- /**
- * Array of DLLs of paths traversing the peer, organized by the
- * offset of the peer on the larger path.
- */
- struct CadetPeerPathEntry **path_heads;
-
- /**
- * Array of DLL of paths traversing the peer, organized by the
- * offset of the peer on the larger path.
- */
- struct CadetPeerPathEntry **path_tails;
-
- /**
- * Notifications to call when @e core_mq changes.
- */
- struct GCP_MessageQueueManager *mqm_head;
-
- /**
- * Notifications to call when @e core_mq changes.
- */
- struct GCP_MessageQueueManager *mqm_tail;
-
- /**
- * Pointer to first "ready" entry in @e mqm_head.
- */
- struct GCP_MessageQueueManager *mqm_ready_ptr;
-
- /**
- * MIN-heap of paths owned by this peer (they also end at this
- * peer). Ordered by desirability.
- */
- struct GNUNET_CONTAINER_Heap *path_heap;
-
- /**
- * Handle to stop the DHT search for paths to this peer
- */
- struct GCD_search_handle *search_h;
-
- /**
- * Task to clean up @e path_heap asynchronously.
- */
- struct GNUNET_SCHEDULER_Task *heap_cleanup_task;
-
- /**
- * Task to destroy this entry.
- */
- struct GNUNET_SCHEDULER_Task *destroy_task;
-
- /**
- * Tunnel to this peer, if any.
- */
- struct CadetTunnel *t;
-
- /**
- * Connections that go through this peer; indexed by tid.
- */
- struct GNUNET_CONTAINER_MultiShortmap *connections;
-
- /**
- * Handle for core transmissions.
- */
- struct GNUNET_MQ_Handle *core_mq;
-
- /**
- * Hello message of the peer.
- */
- struct GNUNET_HELLO_Message *hello;
-
- /**
- * Handle to us offering the HELLO to the transport.
- */
- struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
-
- /**
- * Handle to our ATS request asking ATS to suggest an address
- * to TRANSPORT for this peer (to establish a direct link).
- */
- struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
-
- /**
- * How many messages are in the queue to this peer.
- */
- unsigned int queue_n;
-
- /**
- * How many paths do we have to this peer (in all @e path_heads DLLs combined).
- */
- unsigned int num_paths;
-
- /**
- * Sum over all of the offsets of all of the paths in the @a path_heads DLLs.
- * Used to speed-up @GCP_get_desirability_of_path() calculation.
- */
- unsigned int off_sum;
-
- /**
- * Number of message queue managers of this peer that have a message in waiting.
- *
- * Used to quickly see if we need to bother scanning the @e msm_head DLL.
- * TODO: could be replaced by another DLL that would then allow us to avoid
- * the O(n)-scan of the DLL for ready entries!
- */
- unsigned int mqm_ready_counter;
-
- /**
- * Current length of the @e path_heads and @path_tails arrays.
- * The arrays should be grown as needed.
- */
- unsigned int path_dll_length;
-
-};
-
-
-/**
- * Get the static string for a peer ID.
- *
- * @param cp Peer.
- * @return Static string for it's ID.
- */
-const char *
-GCP_2s (const struct CadetPeer *cp)
-{
- static char buf[32];
-
- GNUNET_snprintf (buf,
- sizeof (buf),
- "P(%s)",
- GNUNET_i2s (&cp->pid));
- return buf;
-}
-
-
-/**
- * Calculate how desirable a path is for @a cp if @a cp
- * is at offset @a off.
- *
- * The 'desirability_table.c' program can be used to compute a list of
- * sample outputs for different scenarios. Basically, we score paths
- * lower if there are many alternatives, and higher if they are
- * shorter than average, and very high if they are much shorter than
- * average and without many alternatives.
- *
- * @param cp a peer reachable via a path
- * @param off offset of @a cp in the path
- * @return score how useful a path is to reach @a cp,
- * positive scores mean path is more desirable
- */
-double
-GCP_get_desirability_of_path (struct CadetPeer *cp,
- unsigned int off)
-{
- unsigned int num_alts = cp->num_paths;
- unsigned int off_sum;
- double avg_sum;
- double path_delta;
- double weight_alts;
-
- GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */
- GNUNET_assert (0 != cp->path_dll_length);
-
- /* We maintain 'off_sum' in 'peer' and thereby
- avoid the SLOW recalculation each time. Kept here
- just to document what is going on. */
-#if SLOW
- off_sum = 0;
- for (unsigned int j=0;j<cp->path_dll_length;j++)
- for (struct CadetPeerPathEntry *pe = cp->path_heads[j];
- NULL != pe;
- pe = pe->next)
- off_sum += j;
- GNUNET_assert (off_sum == cp->off_sum);
-#else
- off_sum = cp->off_sum;
-#endif
- avg_sum = off_sum * 1.0 / cp->path_dll_length;
- path_delta = off - avg_sum;
- /* path_delta positiv: path off of peer above average (bad path for peer),
- path_delta negativ: path off of peer below average (good path for peer) */
- if (path_delta <= - 1.0)
- weight_alts = - num_alts / path_delta; /* discount alternative paths */
- else if (path_delta >= 1.0)
- weight_alts = num_alts * path_delta; /* overcount alternative paths */
- else
- weight_alts = num_alts; /* count alternative paths normally */
-
-
- /* off+1: long paths are generally harder to find and thus count
- a bit more as they get longer. However, above-average paths
- still need to count less, hence the squaring of that factor. */
- return (off + 1.0) / (weight_alts * weight_alts);
-}
-
-
-/**
- * This peer is no longer be needed, clean it up now.
- *
- * @param cls peer to clean up
- */
-static void
-destroy_peer (void *cls)
-{
- struct CadetPeer *cp = cls;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Destroying state about peer %s\n",
- GCP_2s (cp));
- cp->destroy_task = NULL;
- GNUNET_assert (NULL == cp->t);
- GNUNET_assert (NULL == cp->core_mq);
- GNUNET_assert (0 == cp->num_paths);
- for (unsigned int i=0;i<cp->path_dll_length;i++)
- GNUNET_assert (NULL == cp->path_heads[i]);
- GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multipeermap_remove (peers,
- &cp->pid,
- cp));
- GNUNET_free_non_null (cp->path_heads);
- GNUNET_free_non_null (cp->path_tails);
- cp->path_dll_length = 0;
- if (NULL != cp->search_h)
- {
- GCD_search_stop (cp->search_h);
- cp->search_h = NULL;
- }
- /* FIXME: clean up search_delayedXXX! */
-
- if (NULL != cp->hello_offer)
- {
- GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
- cp->hello_offer = NULL;
- }
- if (NULL != cp->connectivity_suggestion)
- {
- GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
- cp->connectivity_suggestion = NULL;
- }
- GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
- if (NULL != cp->path_heap)
- {
- GNUNET_CONTAINER_heap_destroy (cp->path_heap);
- cp->path_heap = NULL;
- }
- if (NULL != cp->heap_cleanup_task)
- {
- GNUNET_SCHEDULER_cancel (cp->heap_cleanup_task);
- cp->heap_cleanup_task = NULL;
- }
- GNUNET_free_non_null (cp->hello);
- /* Peer should not be freed if paths exist; if there are no paths,
- there ought to be no connections, and without connections, no
- notifications. Thus we can assert that mqm_head is empty at this
- point. */
- GNUNET_assert (NULL == cp->mqm_head);
- GNUNET_assert (NULL == cp->mqm_ready_ptr);
- GNUNET_free (cp);
-}
-
-
-/**
- * This peer is now on more "active" duty, activate processes related to it.
- *
- * @param cp the more-active peer
- */
-static void
-consider_peer_activate (struct CadetPeer *cp)
-{
- uint32_t strength;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Updating peer %s activation state (%u connections)%s%s\n",
- GCP_2s (cp),
- GNUNET_CONTAINER_multishortmap_size (cp->connections),
- (NULL == cp->t) ? "" : " with tunnel",
- (NULL == cp->core_mq) ? "" : " with CORE link");
- if (NULL != cp->destroy_task)
- {
- /* It's active, do not destory! */
- GNUNET_SCHEDULER_cancel (cp->destroy_task);
- cp->destroy_task = NULL;
- }
- if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
- (NULL == cp->t) )
- {
- /* We're just on a path or directly connected; don't bother too much */
- if (NULL != cp->connectivity_suggestion)
- {
- GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
- cp->connectivity_suggestion = NULL;
- }
- if (NULL != cp->search_h)
- {
- GCD_search_stop (cp->search_h);
- cp->search_h = NULL;
- }
- return;
- }
- if (NULL == cp->core_mq)
- {
- /* Lacks direct connection, try to create one by querying the DHT */
- if ( (NULL == cp->search_h) &&
- (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
- cp->search_h
- = GCD_search (&cp->pid);
- }
- else
- {
- /* Have direct connection, stop DHT search if active */
- if (NULL != cp->search_h)
- {
- GCD_search_stop (cp->search_h);
- cp->search_h = NULL;
- }
- }
-
- /* If we have a tunnel, our urge for connections is much bigger */
- strength = (NULL != cp->t) ? 32 : 1;
- if (NULL != cp->connectivity_suggestion)
- GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
- cp->connectivity_suggestion
- = GNUNET_ATS_connectivity_suggest (ats_ch,
- &cp->pid,
- strength);
-}
-
-
-/**
- * This peer may no longer be needed, consider cleaning it up.
- *
- * @param cp peer to clean up
- */
-static void
-consider_peer_destroy (struct CadetPeer *cp);
-
-
-/**
- * We really no longere care about a peer, stop hogging memory with paths to it.
- * Afterwards, see if there is more to be cleaned up about this peer.
- *
- * @param cls a `struct CadetPeer`.
- */
-static void
-drop_paths (void *cls)
-{
- struct CadetPeer *cp = cls;
- struct CadetPeerPath *path;
-
- cp->destroy_task = NULL;
- while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
- GCPP_release (path);
- consider_peer_destroy (cp);
-}
-
-
-/**
- * This peer may no longer be needed, consider cleaning it up.
- *
- * @param cp peer to clean up
- */
-static void
-consider_peer_destroy (struct CadetPeer *cp)
-{
- struct GNUNET_TIME_Relative exp;
-
- if (NULL != cp->destroy_task)
- {
- GNUNET_SCHEDULER_cancel (cp->destroy_task);
- cp->destroy_task = NULL;
- }
- if (NULL != cp->t)
- return; /* still relevant! */
- if (NULL != cp->core_mq)
- return; /* still relevant! */
- if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
- return; /* still relevant! */
- if ( (NULL != cp->path_heap) &&
- (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) )
- {
- cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
- &drop_paths,
- cp);
- return;
- }
- if (0 != cp->num_paths)
- return; /* still relevant! */
- if (NULL != cp->hello)
- {
- /* relevant only until HELLO expires */
- exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
- cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
- &destroy_peer,
- cp);
- return;
- }
- cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
- &destroy_peer,
- cp);
-}
-
-
-/**
- * Set the message queue to @a mq for peer @a cp and notify watchers.
- *
- * @param cp peer to modify
- * @param mq message queue to set (can be NULL)
- */
-void
-GCP_set_mq (struct CadetPeer *cp,
- struct GNUNET_MQ_Handle *mq)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Message queue for peer %s is now %p\n",
- GCP_2s (cp),
- mq);
- cp->core_mq = mq;
- for (struct GCP_MessageQueueManager *mqm = cp->mqm_head, *next;
- NULL != mqm;
- mqm = next)
- {
- /* Save next pointer in case mqm gets freed by the callback */
- next = mqm->next;
- if (NULL == mq)
- {
- if (NULL != mqm->env)
- {
- GNUNET_MQ_discard (mqm->env);
- mqm->env = NULL;
- mqm->cb (mqm->cb_cls,
- GNUNET_SYSERR);
- }
- else
- {
- mqm->cb (mqm->cb_cls,
- GNUNET_NO);
- }
- }
- else
- {
- GNUNET_assert (NULL == mqm->env);
- mqm->cb (mqm->cb_cls,
- GNUNET_YES);
- }
- }
- if ( (NULL != mq) ||
- (NULL != cp->t) )
- consider_peer_activate (cp);
- else
- consider_peer_destroy (cp);
-
- if ( (NULL != mq) &&
- (NULL != cp->t) )
- {
- /* have a new, direct path to the target, notify tunnel */
- struct CadetPeerPath *path;
-
- path = GCPP_get_path_from_route (1,
- &cp->pid);
- GCT_consider_path (cp->t,
- path,
- 0);
- }
-}
-
-
-/**
- * Debug function should NEVER return true in production code, useful to
- * simulate losses for testcases.
- *
- * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
- */
-static int
-should_I_drop (void)
-{
- if (0 == drop_percent)
- return GNUNET_NO;
- if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
- 101) < drop_percent)
- return GNUNET_YES;
- return GNUNET_NO;
-}
-
-
-/**
- * Function called when CORE took one of the messages from
- * a message queue manager and transmitted it.
- *
- * @param cls the `struct CadetPeeer` where we made progress
- */
-static void
-mqm_send_done (void *cls);
-
-
-/**
- * Transmit current envelope from this @a mqm.
- *
- * @param mqm mqm to transmit message for now
- */
-static void
-mqm_execute (struct GCP_MessageQueueManager *mqm)
-{
- struct CadetPeer *cp = mqm->cp;
-
- /* Move ready pointer to the next entry that might be ready. */
- if ( (mqm == cp->mqm_ready_ptr) &&
- (NULL != mqm->next) )
- cp->mqm_ready_ptr = mqm->next;
- /* Move entry to the end of the DLL, to be fair. */
- if (mqm != cp->mqm_tail)
- {
- GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
- cp->mqm_tail,
- mqm);
- GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
- cp->mqm_tail,
- mqm);
- }
- cp->mqm_ready_counter--;
- if (GNUNET_YES == should_I_drop ())
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "DROPPING message to peer %s from MQM %p\n",
- GCP_2s (cp),
- mqm);
- GNUNET_MQ_discard (mqm->env);
- mqm->env = NULL;
- mqm_send_done (cp);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sending to peer %s from MQM %p\n",
- GCP_2s (cp),
- mqm);
- GNUNET_MQ_send (cp->core_mq,
- mqm->env);
- mqm->env = NULL;
- }
- mqm->cb (mqm->cb_cls,
- GNUNET_YES);
-}
-
-
-/**
- * Find the next ready message in the queue (starting
- * the search from the `cp->mqm_ready_ptr`) and if possible
- * execute the transmission.
- *
- * @param cp peer to try to send the next ready message to
- */
-static void
-send_next_ready (struct CadetPeer *cp)
-{
- struct GCP_MessageQueueManager *mqm;
-
- if (0 == cp->mqm_ready_counter)
- return;
- while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
- (NULL == mqm->env) )
- cp->mqm_ready_ptr = mqm->next;
- if (NULL == mqm)
- return; /* nothing to do */
- mqm_execute (mqm);
-}
-
-
-/**
- * Function called when CORE took one of the messages from
- * a message queue manager and transmitted it.
- *
- * @param cls the `struct CadetPeeer` where we made progress
- */
-static void
-mqm_send_done (void *cls)
-{
- struct CadetPeer *cp = cls;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sending to peer %s completed\n",
- GCP_2s (cp));
- send_next_ready (cp);
-}
-
-
-/**
- * Send the message in @a env to @a cp.
- *
- * @param mqm the message queue manager to use for transmission
- * @param env envelope with the message to send; must NOT
- * yet have a #GNUNET_MQ_notify_sent() callback attached to it
- */
-void
-GCP_send (struct GCP_MessageQueueManager *mqm,
- struct GNUNET_MQ_Envelope *env)
-{
- struct CadetPeer *cp = mqm->cp;
-
- GNUNET_assert (NULL != env);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Queueing message to peer %s in MQM %p\n",
- GCP_2s (cp),
- mqm);
- GNUNET_assert (NULL != cp->core_mq);
- GNUNET_assert (NULL == mqm->env);
- GNUNET_MQ_notify_sent (env,
- &mqm_send_done,
- cp);
- mqm->env = env;
- cp->mqm_ready_counter++;
- if (mqm != cp->mqm_ready_ptr)
- cp->mqm_ready_ptr = cp->mqm_head;
- if (1 == cp->mqm_ready_counter)
- cp->mqm_ready_ptr = mqm;
- if (0 != GNUNET_MQ_get_length (cp->core_mq))
- return;
- send_next_ready (cp);
-}
-
-
-/**
- * Function called to destroy a peer now.
- *
- * @param cls NULL
- * @param pid identity of the peer (unused)
- * @param value the `struct CadetPeer` to clean up
- * @return #GNUNET_OK (continue to iterate)
- */
-static int
-destroy_iterator_cb (void *cls,
- const struct GNUNET_PeerIdentity *pid,
- void *value)
-{
- struct CadetPeer *cp = value;
-
- if (NULL != cp->destroy_task)
- {
- GNUNET_SCHEDULER_cancel (cp->destroy_task);
- cp->destroy_task = NULL;
- }
- destroy_peer (cp);
- return GNUNET_OK;
-}
-
-
-/**
- * Clean up all entries about all peers.
- * Must only be called after all tunnels, CORE-connections and
- * connections are down.
- */
-void
-GCP_destroy_all_peers ()
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Destroying all peers now\n");
- GNUNET_CONTAINER_multipeermap_iterate (peers,
- &destroy_iterator_cb,
- NULL);
-}
-
-
-/**
- * Drop all paths owned by this peer, and do not
- * allow new ones to be added: We are shutting down.
- *
- * @param cp peer to drop paths to
- */
-void
-GCP_drop_owned_paths (struct CadetPeer *cp)
-{
- struct CadetPeerPath *path;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Destroying all paths to %s\n",
- GCP_2s (cp));
- while (NULL != (path =
- GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
- GCPP_release (path);
- GNUNET_CONTAINER_heap_destroy (cp->path_heap);
- cp->path_heap = NULL;
-}
-
-
-/**
- * Add an entry to the DLL of all of the paths that this peer is on.
- *
- * @param cp peer to modify
- * @param entry an entry on a path
- * @param off offset of this peer on the path
- */
-void
-GCP_path_entry_add (struct CadetPeer *cp,
- struct CadetPeerPathEntry *entry,
- unsigned int off)
-{
- GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
- off));
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Discovered that peer %s is on path %s at offset %u\n",
- GCP_2s (cp),
- GCPP_2s (entry->path),
- off);
- if (off >= cp->path_dll_length)
- {
- unsigned int len = cp->path_dll_length;
-
- GNUNET_array_grow (cp->path_heads,
- len,
- off + 4);
- GNUNET_array_grow (cp->path_tails,
- cp->path_dll_length,
- off + 4);
- }
- GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
- cp->path_tails[off],
- entry);
- cp->off_sum += off;
- cp->num_paths++;
-
- /* If we have a tunnel to this peer, tell the tunnel that there is a
- new path available. */
- if (NULL != cp->t)
- GCT_consider_path (cp->t,
- entry->path,
- off);
-
- if ( (NULL != cp->search_h) &&
- (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
- {
- /* Now I have enough paths, stop search */
- GCD_search_stop (cp->search_h);
- cp->search_h = NULL;
- }
- if (NULL != cp->destroy_task)
- {
- /* paths changed, this resets the destroy timeout counter
- and aborts a destroy task that may no longer be valid
- to have (as we now have more paths via this peer). */
- consider_peer_destroy (cp);
- }
-}
-
-
-/**
- * Remove an entry from the DLL of all of the paths that this peer is on.
- *
- * @param cp peer to modify
- * @param entry an entry on a path
- * @param off offset of this peer on the path
- */
-void
-GCP_path_entry_remove (struct CadetPeer *cp,
- struct CadetPeerPathEntry *entry,
- unsigned int off)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Removing knowledge about peer %s beging on path %s at offset %u\n",
- GCP_2s (cp),
- GCPP_2s (entry->path),
- off);
- GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
- cp->path_tails[off],
- entry);
- GNUNET_assert (0 < cp->num_paths);
- cp->off_sum -= off;
- cp->num_paths--;
- if ( (NULL == cp->core_mq) &&
- (NULL != cp->t) &&
- (NULL == cp->search_h) &&
- (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
- cp->search_h
- = GCD_search (&cp->pid);
- if (NULL == cp->destroy_task)
- {
- /* paths changed, we might now be ready for destruction, check again */
- consider_peer_destroy (cp);
- }
-}
-
-
-/**
- * Prune down the number of paths to this peer, we seem to
- * have way too many.
- *
- * @param cls the `struct CadetPeer` to maintain the path heap for
- */
-static void
-path_heap_cleanup (void *cls)
-{
- struct CadetPeer *cp = cls;
- struct CadetPeerPath *root;
-
- cp->heap_cleanup_task = NULL;
- while (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
- 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
- {
- /* Now we have way too many, drop least desirable UNLESS it is in use!
- (Note that this intentionally keeps highly desireable, but currently
- unused paths around in the hope that we might be able to switch, even
- if the number of paths exceeds the threshold.) */
- root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
- GNUNET_assert (NULL != root);
- if (NULL !=
- GCPP_get_connection (root,
- cp,
- GCPP_get_length (root) - 1))
- break; /* can't fix */
- /* Got plenty of paths to this destination, and this is a low-quality
- one that we don't care about. Allow it to die. */
- GNUNET_assert (root ==
- GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
- GCPP_release (root);
- }
-}
-
-
-/**
- * Try adding a @a path to this @a peer. If the peer already
- * has plenty of paths, return NULL.
- *
- * @param cp peer to which the @a path leads to
- * @param path a path looking for an owner; may not be fully initialized yet!
- * @param off offset of @a cp in @a path
- * @param force force attaching the path
- * @return NULL if this peer does not care to become a new owner,
- * otherwise the node in the peer's path heap for the @a path.
- */
-struct GNUNET_CONTAINER_HeapNode *
-GCP_attach_path (struct CadetPeer *cp,
- struct CadetPeerPath *path,
- unsigned int off,
- int force)
-{
- GNUNET_CONTAINER_HeapCostType desirability;
- struct CadetPeerPath *root;
- GNUNET_CONTAINER_HeapCostType root_desirability;
- struct GNUNET_CONTAINER_HeapNode *hn;
-
- GNUNET_assert (off == GCPP_get_length (path) - 1);
- GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
- off));
- if (NULL == cp->path_heap)
- {
- /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
- GNUNET_assert (GNUNET_NO == force);
- return NULL;
- }
- desirability = GCPP_get_desirability (path);
- if (GNUNET_NO == force)
- {
- /* FIXME: desirability is not yet initialized; tricky! */
- if (GNUNET_NO ==
- GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
- (void **) &root,
- &root_desirability))
- {
- root = NULL;
- root_desirability = 0;
- }
-
- if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
- (desirability < root_desirability) )
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Decided to not attach path %p to peer %s due to undesirability\n",
- GCPP_2s (path),
- GCP_2s (cp));
- return NULL;
- }
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Attaching path %s to peer %s (%s)\n",
- GCPP_2s (path),
- GCP_2s (cp),
- (GNUNET_NO == force) ? "desirable" : "forced");
-
- /* Yes, we'd like to add this path, add to our heap */
- hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
- path,
- desirability);
-
- /* Consider maybe dropping other paths because of the new one */
- if ( (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
- 2 * DESIRED_CONNECTIONS_PER_TUNNEL) &&
- (NULL != cp->heap_cleanup_task) )
- cp->heap_cleanup_task = GNUNET_SCHEDULER_add_now (&path_heap_cleanup,
- cp);
- return hn;
-}
-
-
-/**
- * This peer can no longer own @a path as the path
- * has been extended and a peer further down the line
- * is now the new owner.
- *
- * @param cp old owner of the @a path
- * @param path path where the ownership is lost
- * @param hn note in @a cp's path heap that must be deleted
- */
-void
-GCP_detach_path (struct CadetPeer *cp,
- struct CadetPeerPath *path,
- struct GNUNET_CONTAINER_HeapNode *hn)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Detatching path %s from peer %s\n",
- GCPP_2s (path),
- GCP_2s (cp));
- GNUNET_assert (path ==
- GNUNET_CONTAINER_heap_remove_node (hn));
-}
-
-
-/**
- * Add a @a connection to this @a cp.
- *
- * @param cp peer via which the @a connection goes
- * @param cc the connection to add
- */
-void
-GCP_add_connection (struct CadetPeer *cp,
- struct CadetConnection *cc)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Adding connection %s to peer %s\n",
- GCC_2s (cc),
- GCP_2s (cp));
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CONTAINER_multishortmap_put (cp->connections,
- &GCC_get_id (cc)->connection_of_tunnel,
- cc,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
- if (NULL != cp->destroy_task)
- {
- GNUNET_SCHEDULER_cancel (cp->destroy_task);
- cp->destroy_task = NULL;
- }
-}
-
-
-/**
- * Remove a @a connection that went via this @a cp.
- *
- * @param cp peer via which the @a connection went
- * @param cc the connection to remove
- */
-void
-GCP_remove_connection (struct CadetPeer *cp,
- struct CadetConnection *cc)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Removing connection %s from peer %s\n",
- GCC_2s (cc),
- GCP_2s (cp));
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multishortmap_remove (cp->connections,
- &GCC_get_id (cc)->connection_of_tunnel,
- cc));
- consider_peer_destroy (cp);
-}
-
-
-/**
- * Retrieve the CadetPeer stucture associated with the
- * peer. Optionally create one and insert it in the appropriate
- * structures if the peer is not known yet.
- *
- * @param peer_id Full identity of the peer.
- * @param create #GNUNET_YES if a new peer should be created if unknown.
- * #GNUNET_NO to return NULL if peer is unknown.
- * @return Existing or newly created peer structure.
- * NULL if unknown and not requested @a create
- */
-struct CadetPeer *
-GCP_get (const struct GNUNET_PeerIdentity *peer_id,
- int create)
-{
- struct CadetPeer *cp;
-
- cp = GNUNET_CONTAINER_multipeermap_get (peers,
- peer_id);
- if (NULL != cp)
- return cp;
- if (GNUNET_NO == create)
- return NULL;
- cp = GNUNET_new (struct CadetPeer);
- cp->pid = *peer_id;
- cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
- GNUNET_YES);
- cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multipeermap_put (peers,
- &cp->pid,
- cp,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Creating peer %s\n",
- GCP_2s (cp));
- return cp;
-}
-
-
-/**
- * Obtain the peer identity for a `struct CadetPeer`.
- *
- * @param cp our peer handle
- * @return the peer identity
- */
-const struct GNUNET_PeerIdentity *
-GCP_get_id (struct CadetPeer *cp)
-{
- return &cp->pid;
-}
-
-
-/**
- * Iterate over all known peers.
- *
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
- void *cls)
-{
- GNUNET_CONTAINER_multipeermap_iterate (peers,
- iter,
- cls);
-}
-
-
-/**
- * Count the number of known paths toward the peer.
- *
- * @param cp Peer to get path info.
- * @return Number of known paths.
- */
-unsigned int
-GCP_count_paths (const struct CadetPeer *cp)
-{
- return cp->num_paths;
-}
-
-
-/**
- * Iterate over the paths to a peer.
- *
- * @param cp Peer to get path info.
- * @param callback Function to call for every path.
- * @param callback_cls Closure for @a callback.
- * @return Number of iterated paths.
- */
-unsigned int
-GCP_iterate_paths (struct CadetPeer *cp,
- GCP_PathIterator callback,
- void *callback_cls)
-{
- unsigned int ret = 0;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Iterating over paths to peer %s%s\n",
- GCP_2s (cp),
- (NULL == cp->core_mq) ? "" : " including direct link");
- if (NULL != cp->core_mq)
- {
- struct CadetPeerPath *path;
-
- path = GCPP_get_path_from_route (1,
- &cp->pid);
- ret++;
- if (GNUNET_NO ==
- callback (callback_cls,
- path,
- 0))
- return ret;
- }
- for (unsigned int i=0;i<cp->path_dll_length;i++)
- {
- for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
- NULL != pe;
- pe = pe->next)
- {
- ret++;
- if (GNUNET_NO ==
- callback (callback_cls,
- pe->path,
- i))
- return ret;
- }
- }
- return ret;
-}
-
-
-/**
- * Iterate over the paths to @a cp where
- * @a cp is at distance @a dist from us.
- *
- * @param cp Peer to get path info.
- * @param dist desired distance of @a cp to us on the path
- * @param callback Function to call for every path.
- * @param callback_cls Closure for @a callback.
- * @return Number of iterated paths.
- */
-unsigned int
-GCP_iterate_paths_at (struct CadetPeer *cp,
- unsigned int dist,
- GCP_PathIterator callback,
- void *callback_cls)
-{
- unsigned int ret = 0;
-
- if (dist >= cp->path_dll_length)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Asked to look for paths at distance %u, but maximum for me is < %u\n",
- dist,
- cp->path_dll_length);
- return 0;
- }
- for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
- NULL != pe;
- pe = pe->next)
- {
- if (GNUNET_NO ==
- callback (callback_cls,
- pe->path,
- dist))
- return ret;
- ret++;
- }
- return ret;
-}
-
-
-/**
- * Get the tunnel towards a peer.
- *
- * @param cp Peer to get from.
- * @param create #GNUNET_YES to create a tunnel if we do not have one
- * @return Tunnel towards peer.
- */
-struct CadetTunnel *
-GCP_get_tunnel (struct CadetPeer *cp,
- int create)
-{
- if (NULL == cp)
- return NULL;
- if ( (NULL != cp->t) ||
- (GNUNET_NO == create) )
- return cp->t;
- cp->t = GCT_create_tunnel (cp);
- consider_peer_activate (cp);
- return cp->t;
-}
-
-
-/**
- * Hello offer was passed to the transport service. Mark it
- * as done.
- *
- * @param cls the `struct CadetPeer` where the offer completed
- */
-static void
-hello_offer_done (void *cls)
-{
- struct CadetPeer *cp = cls;
-
- cp->hello_offer = NULL;
-}
-
-
-/**
- * We got a HELLO for a @a peer, remember it, and possibly
- * trigger adequate actions (like trying to connect).
- *
- * @param cp the peer we got a HELLO for
- * @param hello the HELLO to remember
- */
-void
-GCP_set_hello (struct CadetPeer *cp,
- const struct GNUNET_HELLO_Message *hello)
-{
- struct GNUNET_HELLO_Message *mrg;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Got %u byte HELLO for peer %s\n",
- (unsigned int) GNUNET_HELLO_size (hello),
- GCP_2s (cp));
- if (NULL != cp->hello_offer)
- {
- GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
- cp->hello_offer = NULL;
- }
- if (NULL != cp->hello)
- {
- mrg = GNUNET_HELLO_merge (hello,
- cp->hello);
- GNUNET_free (cp->hello);
- cp->hello = mrg;
- }
- else
- {
- cp->hello = GNUNET_memdup (hello,
- GNUNET_HELLO_size (hello));
- }
- cp->hello_offer
- = GNUNET_TRANSPORT_offer_hello (cfg,
- GNUNET_HELLO_get_header (cp->hello) ,
- &hello_offer_done,
- cp);
- /* New HELLO means cp's destruction time may change... */
- consider_peer_destroy (cp);
-}
-
-
-/**
- * The tunnel to the given peer no longer exists, remove it from our
- * data structures, and possibly clean up the peer itself.
- *
- * @param cp the peer affected
- * @param t the dead tunnel
- */
-void
-GCP_drop_tunnel (struct CadetPeer *cp,
- struct CadetTunnel *t)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Dropping tunnel %s to peer %s\n",
- GCT_2s (t),
- GCP_2s (cp));
- GNUNET_assert (cp->t == t);
- cp->t = NULL;
- consider_peer_destroy (cp);
-}
-
-
-/**
- * Test if @a cp has a core-level connection
- *
- * @param cp peer to test
- * @return #GNUNET_YES if @a cp has a core-level connection
- */
-int
-GCP_has_core_connection (struct CadetPeer *cp)
-{
- return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
-}
-
-
-/**
- * Start message queue change notifications.
- *
- * @param cp peer to notify for
- * @param cb function to call if mq becomes available or unavailable
- * @param cb_cls closure for @a cb
- * @return handle to cancel request
- */
-struct GCP_MessageQueueManager *
-GCP_request_mq (struct CadetPeer *cp,
- GCP_MessageQueueNotificationCallback cb,
- void *cb_cls)
-{
- struct GCP_MessageQueueManager *mqm;
-
- mqm = GNUNET_new (struct GCP_MessageQueueManager);
- mqm->cb = cb;
- mqm->cb_cls = cb_cls;
- mqm->cp = cp;
- GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
- cp->mqm_tail,
- mqm);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Creating MQM %p for peer %s\n",
- mqm,
- GCP_2s (cp));
- if (NULL != cp->core_mq)
- cb (cb_cls,
- GNUNET_YES);
- return mqm;
-}
-
-
-/**
- * Stops message queue change notifications.
- *
- * @param mqm handle matching request to cancel
- * @param last_env final message to transmit, or NULL
- */
-void
-GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
- struct GNUNET_MQ_Envelope *last_env)
-{
- struct CadetPeer *cp = mqm->cp;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Destroying MQM %p for peer %s%s\n",
- mqm,
- GCP_2s (cp),
- (NULL == last_env) ? "" : " with last ditch transmission");
- if (NULL != mqm->env)
- GNUNET_MQ_discard (mqm->env);
- if (NULL != last_env)
- {
- if (NULL != cp->core_mq)
- {
- GNUNET_MQ_notify_sent (last_env,
- &mqm_send_done,
- cp);
- GNUNET_MQ_send (cp->core_mq,
- last_env);
- }
- else
- {
- GNUNET_MQ_discard (last_env);
- }
- }
- if (cp->mqm_ready_ptr == mqm)
- cp->mqm_ready_ptr = mqm->next;
- GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
- cp->mqm_tail,
- mqm);
- GNUNET_free (mqm);
-}
-
-
-/**
- * Send the message in @a env to @a cp, overriding queueing logic.
- * This function should only be used to send error messages outside
- * of flow and congestion control, similar to ICMP. Note that
- * the envelope may be silently discarded as well.
- *
- * @param cp peer to send the message to
- * @param env envelope with the message to send
- */
-void
-GCP_send_ooo (struct CadetPeer *cp,
- struct GNUNET_MQ_Envelope *env)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sending message to %s out of management\n",
- GCP_2s (cp));
- if (NULL == cp->core_mq)
- {
- GNUNET_MQ_discard (env);
- return;
- }
- GNUNET_MQ_notify_sent (env,
- &mqm_send_done,
- cp);
- GNUNET_MQ_send (cp->core_mq,
- env);
-}
-
-
-
-
-/* end of gnunet-service-cadet-new_peer.c */
diff --git a/src/cadet/gnunet-service-cadet-new_peer.h b/src/cadet/gnunet-service-cadet-new_peer.h
deleted file mode 100644
index e1d6fc33a5..0000000000
--- a/src/cadet/gnunet-service-cadet-new_peer.h
+++ /dev/null
@@ -1,394 +0,0 @@
-
-/*
- This file is part of GNUnet.
- Copyright (C) 2001-2017 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new_peer.h
- * @brief Information we track per peer.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#ifndef GNUNET_SERVICE_CADET_PEER_H
-#define GNUNET_SERVICE_CADET_PEER_H
-
-#include "gnunet-service-cadet-new.h"
-#include "gnunet_hello_lib.h"
-
-
-/**
- * Get the static string for a peer ID.
- *
- * @param peer Peer.
- *
- * @return Static string for it's ID.
- */
-const char *
-GCP_2s (const struct CadetPeer *peer);
-
-
-/**
- * Retrieve the CadetPeer stucture associated with the
- * peer. Optionally create one and insert it in the appropriate
- * structures if the peer is not known yet.
- *
- * @param peer_id Full identity of the peer.
- * @param create #GNUNET_YES if a new peer should be created if unknown.
- * #GNUNET_NO to return NULL if peer is unknown.
- * @return Existing or newly created peer structure.
- * NULL if unknown and not requested @a create
- */
-struct CadetPeer *
-GCP_get (const struct GNUNET_PeerIdentity *peer_id,
- int create);
-
-
-/**
- * Calculate how desirable a path is for @a cp if
- * @a cp is at offset @a off in the path.
- *
- * @param cp a peer reachable via a path
- * @param off offset of @a cp in a path
- * @return score how useful a path is to reach @a cp,
- * positive scores mean path is more desirable
- */
-double
-GCP_get_desirability_of_path (struct CadetPeer *cp,
- unsigned int off);
-
-
-/**
- * Obtain the peer identity for a `struct CadetPeer`.
- *
- * @param cp our peer handle
- * @return the peer identity
- */
-const struct GNUNET_PeerIdentity *
-GCP_get_id (struct CadetPeer *cp);
-
-
-/**
- * Iterate over all known peers.
- *
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
- void *cls);
-
-
-/**
- * Count the number of known paths toward the peer.
- *
- * @param cp Peer to get path info.
- * @return Number of known paths.
- */
-unsigned int
-GCP_count_paths (const struct CadetPeer *cp);
-
-
-/**
- * Drop all paths owned by this peer, and do not
- * allow new ones to be added: We are shutting down.
- *
- * @param cp peer to drop paths to
- */
-void
-GCP_drop_owned_paths (struct CadetPeer *cp);
-
-
-/**
- * Peer path iterator.
- *
- * @param cls Closure.
- * @param path Path itself
- * @param off offset of the target peer in @a path
- * @return #GNUNET_YES if should keep iterating.
- * #GNUNET_NO otherwise.
- */
-typedef int
-(*GCP_PathIterator) (void *cls,
- struct CadetPeerPath *path,
- unsigned int off);
-
-
-/**
- * Iterate over the paths to a peer.
- *
- * @param cp Peer to get path info.
- * @param callback Function to call for every path.
- * @param callback_cls Closure for @a callback.
- * @return Number of iterated paths.
- */
-unsigned int
-GCP_iterate_paths (struct CadetPeer *cp,
- GCP_PathIterator callback,
- void *callback_cls);
-
-
-/**
- * Iterate over the paths to @a peer where
- * @a peer is at distance @a dist from us.
- *
- * @param cp Peer to get path info.
- * @param dist desired distance of @a peer to us on the path
- * @param callback Function to call for every path.
- * @param callback_cls Closure for @a callback.
- * @return Number of iterated paths.
- */
-unsigned int
-GCP_iterate_paths_at (struct CadetPeer *cp,
- unsigned int dist,
- GCP_PathIterator callback,
- void *callback_cls);
-
-
-/**
- * Remove an entry from the DLL of all of the paths that this peer is on.
- *
- * @param cp peer to modify
- * @param entry an entry on a path
- * @param off offset of this peer on the path
- */
-void
-GCP_path_entry_remove (struct CadetPeer *cp,
- struct CadetPeerPathEntry *entry,
- unsigned int off);
-
-
-/**
- * Add an entry to the DLL of all of the paths that this peer is on.
- *
- * @param cp peer to modify
- * @param entry an entry on a path
- * @param off offset of this peer on the path
- */
-void
-GCP_path_entry_add (struct CadetPeer *cp,
- struct CadetPeerPathEntry *entry,
- unsigned int off);
-
-
-/**
- * Get the tunnel towards a peer.
- *
- * @param cp Peer to get from.
- * @param create #GNUNET_YES to create a tunnel if we do not have one
- * @return Tunnel towards peer.
- */
-struct CadetTunnel *
-GCP_get_tunnel (struct CadetPeer *cp,
- int create);
-
-
-/**
- * The tunnel to the given peer no longer exists, remove it from our
- * data structures, and possibly clean up the peer itself.
- *
- * @param cp the peer affected
- * @param t the dead tunnel
- */
-void
-GCP_drop_tunnel (struct CadetPeer *cp,
- struct CadetTunnel *t);
-
-
-/**
- * Try adding a @a path to this @a cp. If the peer already
- * has plenty of paths, return NULL.
- *
- * @param cp peer to which the @a path leads to
- * @param path a path looking for an owner; may not be fully initialized yet!
- * @param off offset of @a cp in @a path
- * @param force for attaching the path
- * @return NULL if this peer does not care to become a new owner,
- * otherwise the node in the peer's path heap for the @a path.
- */
-struct GNUNET_CONTAINER_HeapNode *
-GCP_attach_path (struct CadetPeer *cp,
- struct CadetPeerPath *path,
- unsigned int off,
- int force);
-
-
-/**
- * This peer can no longer own @a path as the path
- * has been extended and a peer further down the line
- * is now the new owner.
- *
- * @param cp old owner of the @a path
- * @param path path where the ownership is lost
- * @param hn note in @a cp's path heap that must be deleted
- */
-void
-GCP_detach_path (struct CadetPeer *cp,
- struct CadetPeerPath *path,
- struct GNUNET_CONTAINER_HeapNode *hn);
-
-
-/**
- * Add a @a connection to this @a cp.
- *
- * @param cp peer via which the @a connection goes
- * @param cc the connection to add
- */
-void
-GCP_add_connection (struct CadetPeer *cp,
- struct CadetConnection *cc);
-
-
-/**
- * Remove a @a connection that went via this @a cp.
- *
- * @param cp peer via which the @a connection went
- * @param cc the connection to remove
- */
-void
-GCP_remove_connection (struct CadetPeer *cp,
- struct CadetConnection *cc);
-
-
-/**
- * We got a HELLO for a @a cp, remember it, and possibly
- * trigger adequate actions (like trying to connect).
- *
- * @param cp the peer we got a HELLO for
- * @param hello the HELLO to remember
- */
-void
-GCP_set_hello (struct CadetPeer *cp,
- const struct GNUNET_HELLO_Message *hello);
-
-
-/**
- * Clean up all entries about all peers.
- * Must only be called after all tunnels, CORE-connections and
- * connections are down.
- */
-void
-GCP_destroy_all_peers (void);
-
-
-/**
- * Data structure used to track whom we have to notify about changes
- * in our ability to transmit to a given peer.
- *
- * All queue managers will be given equal chance for sending messages
- * to @a cp. This construct this guarantees fairness for access to @a
- * cp among the different message queues. Each connection or route
- * will have its respective message queue managers for each direction.
- */
-struct GCP_MessageQueueManager;
-
-
-/**
- * Function to call with updated message queue object.
- *
- * @param cls closure
- * @param available #GNUNET_YES if sending is now possible,
- * #GNUNET_NO if sending is no longer possible
- * #GNUNET_SYSERR if sending is no longer possible
- * and the last envelope was discarded
- */
-typedef void
-(*GCP_MessageQueueNotificationCallback)(void *cls,
- int available);
-
-
-/**
- * Start message queue change notifications. Will create a new slot
- * to manage the message queue to the given @a cp.
- *
- * @param cp peer to notify for
- * @param cb function to call if mq becomes available or unavailable
- * @param cb_cls closure for @a cb
- * @return handle to cancel request
- */
-struct GCP_MessageQueueManager *
-GCP_request_mq (struct CadetPeer *cp,
- GCP_MessageQueueNotificationCallback cb,
- void *cb_cls);
-
-
-/**
- * Test if @a cp has a core-level connection
- *
- * @param cp peer to test
- * @return #GNUNET_YES if @a cp has a core-level connection
- */
-int
-GCP_has_core_connection (struct CadetPeer *cp);
-
-
-/**
- * Send the message in @a env via a @a mqm. Must only be called at
- * most once after the respective
- * #GCP_MessageQueueNotificationCallback was called with `available`
- * set to #GNUNET_YES, and not after the callback was called with
- * `available` set to #GNUNET_NO or #GNUNET_SYSERR.
- *
- * @param mqm message queue manager for the transmission
- * @param env envelope with the message to send; must NOT
- * yet have a #GNUNET_MQ_notify_sent() callback attached to it
- */
-void
-GCP_send (struct GCP_MessageQueueManager *mqm,
- struct GNUNET_MQ_Envelope *env);
-
-
-/**
- * Send the message in @a env to @a cp, overriding queueing logic.
- * This function should only be used to send error messages outside
- * of flow and congestion control, similar to ICMP. Note that
- * the envelope may be silently discarded as well.
- *
- * @param cp peer to send the message to
- * @param env envelope with the message to send
- */
-void
-GCP_send_ooo (struct CadetPeer *cp,
- struct GNUNET_MQ_Envelope *env);
-
-
-/**
- * Stops message queue change notifications and sends a last message.
- * In practice, this is implemented by sending that @a last_env
- * message immediately (if any), ignoring queue order.
- *
- * @param mqm handle matching request to cancel
- * @param last_env final message to transmit, or NULL
- */
-void
-GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
- struct GNUNET_MQ_Envelope *last_env);
-
-
-/**
- * Set the message queue to @a mq for peer @a cp and notify watchers.
- *
- * @param cp peer to modify
- * @param mq message queue to set (can be NULL)
- */
-void
-GCP_set_mq (struct CadetPeer *cp,
- struct GNUNET_MQ_Handle *mq);
-
-
-#endif
diff --git a/src/cadet/gnunet-service-cadet.c b/src/cadet/gnunet-service-cadet.c
index 3a07f0ee58..a7e1fca472 100644
--- a/src/cadet/gnunet-service-cadet.c
+++ b/src/cadet/gnunet-service-cadet.c
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet.
- Copyright (C) 2001-2013 GNUnet e.V.
+ Copyright (C) 2001-2013, 2017 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
@@ -22,38 +22,82 @@
* @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
+ * @author Christian Grothoff
*
* 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.
+ * - tunnel: encrypted connection to a peer, neighbor or not.
+ * - channel: logical link between two clients, on the same or different peers.
+ * have properties like reliability.
*/
#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.h"
#include "gnunet-service-cadet_channel.h"
#include "gnunet-service-cadet_connection.h"
-#include "gnunet-service-cadet_tunnel.h"
+#include "gnunet-service-cadet_core.h"
#include "gnunet-service-cadet_dht.h"
-#include "gnunet-service-cadet_peer.h"
#include "gnunet-service-cadet_hello.h"
+#include "gnunet-service-cadet_tunnels.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_paths.h"
+
+#define LOG(level, ...) GNUNET_log (level,__VA_ARGS__)
+
+
+/**
+ * Struct containing information about a client of the service
+ */
+struct CadetClient
+{
+ /**
+ * Linked list next
+ */
+ struct CadetClient *next;
+
+ /**
+ * Linked list prev
+ */
+ struct CadetClient *prev;
+
+ /**
+ * Tunnels that belong to this client, indexed by local id,
+ * value is a `struct CadetChannel`.
+ */
+ struct GNUNET_CONTAINER_MultiHashMap32 *channels;
+
+ /**
+ * Handle to communicate with the client
+ */
+ struct GNUNET_MQ_Handle *mq;
+
+ /**
+ * Client handle.
+ */
+ struct GNUNET_SERVICE_Client *client;
+
+ /**
+ * Ports that this client has declared interest in.
+ * Indexed by port, contains *Client.
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *ports;
+ /**
+ * Channel ID to use for the next incoming channel for this client.
+ * Wraps around (in theory).
+ */
+ struct GNUNET_CADET_ClientChannelNumber next_ccn;
+
+ /**
+ * ID of the client, mainly for debug messages. Purely internal to this file.
+ */
+ unsigned int id;
+};
/******************************************************************************/
/*********************** GLOBAL VARIABLES ****************************/
@@ -62,37 +106,317 @@
/****************************** Global variables ******************************/
/**
+ * Handle to our configuration.
+ */
+const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
* Handle to the statistics service.
*/
struct GNUNET_STATISTICS_Handle *stats;
/**
- * Local peer own ID (memory efficient handle).
+ * Handle to communicate with ATS.
*/
-GNUNET_PEER_Id myid;
+struct GNUNET_ATS_ConnectivityHandle *ats_ch;
/**
- * Local peer own ID (full value).
+ * Local peer own ID.
*/
struct GNUNET_PeerIdentity my_full_id;
+/**
+ * Own private key.
+ */
+struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
/**
- * Signal that shutdown is happening: prevent recover measures.
+ * Signal that shutdown is happening: prevent recovery measures.
*/
int shutting_down;
-/*************************** Static global variables **************************/
+/**
+ * DLL with all the clients, head.
+ */
+static struct CadetClient *clients_head;
/**
- * Own private key.
+ * DLL with all the clients, tail.
*/
-static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
+static struct CadetClient *clients_tail;
+/**
+ * Next ID to assign to a client.
+ */
+static unsigned int next_client_id;
+
+/**
+ * All ports clients of this peer have opened.
+ */
+struct GNUNET_CONTAINER_MultiHashMap *open_ports;
+
+/**
+ * Map from ports to channels where the ports were closed at the
+ * time we got the inbound connection.
+ * Indexed by port, contains `struct CadetChannel`.
+ */
+struct GNUNET_CONTAINER_MultiHashMap *loose_channels;
+
+/**
+ * Map from PIDs to `struct CadetPeer` entries.
+ */
+struct GNUNET_CONTAINER_MultiPeerMap *peers;
+
+/**
+ * Map from `struct GNUNET_CADET_ConnectionTunnelIdentifier`
+ * hash codes to `struct CadetConnection` objects.
+ */
+struct GNUNET_CONTAINER_MultiShortmap *connections;
+
+/**
+ * How many messages are needed to trigger an AXOLOTL ratchet advance.
+ */
+unsigned long long ratchet_messages;
+
+/**
+ * How long until we trigger a ratched advance due to time.
+ */
+struct GNUNET_TIME_Relative ratchet_time;
+
+/**
+ * How frequently do we send KEEPALIVE messages on idle connections?
+ */
+struct GNUNET_TIME_Relative keepalive_period;
+
+/**
+ * Set to non-zero values to create random drops to test retransmissions.
+ */
+unsigned long long drop_percent;
+
+
+/**
+ * Send a message to a client.
+ *
+ * @param c client to get the message
+ * @param env envelope with the message
+ */
+void
+GSC_send_to_client (struct CadetClient *c,
+ struct GNUNET_MQ_Envelope *env)
+{
+ GNUNET_MQ_send (c->mq,
+ env);
+}
+
+
+/**
+ * Return identifier for a client as a string.
+ *
+ * @param c client to identify
+ * @return string for debugging
+ */
+const char *
+GSC_2s (struct CadetClient *c)
+{
+ static char buf[32];
+
+ GNUNET_snprintf (buf,
+ sizeof (buf),
+ "Client(%u)",
+ c->id);
+ return buf;
+}
+
+
+/**
+ * Lookup channel of client @a c by @a ccn.
+ *
+ * @param c client to look in
+ * @param ccn channel ID to look up
+ * @return NULL if no such channel exists
+ */
+static struct CadetChannel *
+lookup_channel (struct CadetClient *c,
+ struct GNUNET_CADET_ClientChannelNumber ccn)
+{
+ return GNUNET_CONTAINER_multihashmap32_get (c->channels,
+ ntohl (ccn.channel_of_client));
+}
+
+
+/**
+ * Obtain the next LID to use for incoming connections to
+ * the given client.
+ *
+ * @param c client handle
+ */
+static struct GNUNET_CADET_ClientChannelNumber
+client_get_next_ccn (struct CadetClient *c)
+{
+ struct GNUNET_CADET_ClientChannelNumber ccn = c->next_ccn;
+
+ /* increment until we have a free one... */
+ while (NULL !=
+ lookup_channel (c,
+ ccn))
+ {
+ ccn.channel_of_client
+ = htonl (1 + (ntohl (ccn.channel_of_client)));
+ if (ntohl (ccn.channel_of_client) >=
+ GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+ ccn.channel_of_client = htonl (0);
+ }
+ c->next_ccn.channel_of_client
+ = htonl (1 + (ntohl (ccn.channel_of_client)));
+ return ccn;
+}
+
+
+/**
+ * Bind incoming channel to this client, and notify client about
+ * incoming connection. Caller is responsible for notifying the other
+ * peer about our acceptance of the channel.
+ *
+ * @param c client to bind to
+ * @param ch channel to be bound
+ * @param dest peer that establishes the connection
+ * @param port port number
+ * @param options options
+ * @return local channel number assigned to the new client
+ */
+struct GNUNET_CADET_ClientChannelNumber
+GSC_bind (struct CadetClient *c,
+ struct CadetChannel *ch,
+ struct CadetPeer *dest,
+ const struct GNUNET_HashCode *port,
+ uint32_t options)
+{
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_CADET_LocalChannelCreateMessage *cm;
+ struct GNUNET_CADET_ClientChannelNumber ccn;
+
+ ccn = client_get_next_ccn (c);
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap32_put (c->channels,
+ ntohl (ccn.channel_of_client),
+ ch,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Accepting incoming %s from %s on open port %s (%u), assigning ccn %X\n",
+ GCCH_2s (ch),
+ GCP_2s (dest),
+ GNUNET_h2s (port),
+ (uint32_t) ntohl (options),
+ (uint32_t) ntohl (ccn.channel_of_client));
+ /* notify local client about incoming connection! */
+ env = GNUNET_MQ_msg (cm,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
+ cm->ccn = ccn;
+ cm->port = *port;
+ cm->opt = htonl (options);
+ cm->peer = *GCP_get_id (dest);
+ GSC_send_to_client (c,
+ env);
+ return ccn;
+}
+
+
+/**
+ * Callback invoked on all peers to destroy all tunnels
+ * that may still exist.
+ *
+ * @param cls NULL
+ * @param pid identify of a peer
+ * @param value a `struct CadetPeer` that may still have a tunnel
+ * @return #GNUNET_OK (iterate over all entries)
+ */
+static int
+destroy_tunnels_now (void *cls,
+ const struct GNUNET_PeerIdentity *pid,
+ void *value)
+{
+ struct CadetPeer *cp = value;
+ struct CadetTunnel *t = GCP_get_tunnel (cp,
+ GNUNET_NO);
+
+ if (NULL != t)
+ GCT_destroy_tunnel_now (t);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Callback invoked on all peers to destroy all tunnels
+ * that may still exist.
+ *
+ * @param cls NULL
+ * @param pid identify of a peer
+ * @param value a `struct CadetPeer` that may still have a tunnel
+ * @return #GNUNET_OK (iterate over all entries)
+ */
+static int
+destroy_paths_now (void *cls,
+ const struct GNUNET_PeerIdentity *pid,
+ void *value)
+{
+ struct CadetPeer *cp = value;
+
+ GCP_drop_owned_paths (cp);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Shutdown everything once the clients have disconnected.
+ */
+static void
+shutdown_rest ()
+{
+ if (NULL != stats)
+ {
+ GNUNET_STATISTICS_destroy (stats,
+ GNUNET_NO);
+ stats = NULL;
+ }
+ if (NULL != open_ports)
+ {
+ GNUNET_CONTAINER_multihashmap_destroy (open_ports);
+ open_ports = NULL;
+ }
+ if (NULL != loose_channels)
+ {
+ GNUNET_CONTAINER_multihashmap_destroy (loose_channels);
+ loose_channels = NULL;
+ }
+ /* Destroy tunnels. Note that all channels must be destroyed first! */
+ GCP_iterate_all (&destroy_tunnels_now,
+ NULL);
+ /* All tunnels, channels, connections and CORE must be down before this point. */
+ GCP_iterate_all (&destroy_paths_now,
+ NULL);
+ /* All paths, tunnels, channels, connections and CORE must be down before this point. */
+ GCP_destroy_all_peers ();
+ if (NULL != peers)
+ {
+ GNUNET_CONTAINER_multipeermap_destroy (peers);
+ peers = NULL;
+ }
+ if (NULL != connections)
+ {
+ GNUNET_CONTAINER_multishortmap_destroy (connections);
+ connections = NULL;
+ }
+ if (NULL != ats_ch)
+ {
+ GNUNET_ATS_connectivity_done (ats_ch);
+ ats_ch = NULL;
+ }
+ GCD_shutdown ();
+ GCH_shutdown ();
+ GNUNET_free_non_null (my_private_key);
+ my_private_key = NULL;
+}
-/******************************************************************************/
-/************************ MAIN FUNCTIONS ****************************/
-/******************************************************************************/
/**
* Task run during shutdown.
@@ -102,83 +426,1071 @@ static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
static void
shutdown_task (void *cls)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutting down\n");
-
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Shutting down\n");
shutting_down = GNUNET_YES;
+ GCO_shutdown ();
+ if (NULL == clients_head)
+ shutdown_rest ();
+}
- GML_shutdown ();
- GCH_shutdown ();
- GCC_shutdown ();
- GCT_shutdown ();
- GCD_shutdown ();
- GCP_shutdown ();
- GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
- stats = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shut down\n");
+/**
+ * We had a remote connection @a value to port @a port before
+ * client @a cls opened port @a port. Bind them now.
+ *
+ * @param cls the `struct CadetClient`
+ * @param port the port
+ * @param value the `struct CadetChannel`
+ * @return #GNUNET_YES (iterate over all such channels)
+ */
+static int
+bind_loose_channel (void *cls,
+ const struct GNUNET_HashCode *port,
+ void *value)
+{
+ struct CadetClient *c = cls;
+ struct CadetChannel *ch = value;
+
+ GCCH_bind (ch,
+ c);
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (loose_channels,
+ port,
+ value));
+ return GNUNET_YES;
}
/**
- * Process cadet requests.
+ * Handle port open request. Creates a mapping from the
+ * port to the respective client and checks whether we have
+ * loose channels trying to bind to the port. If so, those
+ * are bound.
*
- * @param cls closure
- * @param server the initialized server
- * @param c configuration to use
+ * @param cls Identification of the client.
+ * @param pmsg The actual message.
*/
static void
-run (void *cls, struct GNUNET_SERVER_Handle *server,
- const struct GNUNET_CONFIGURATION_Handle *c)
+handle_port_open (void *cls,
+ const struct GNUNET_CADET_PortMessage *pmsg)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting to run\n");
+ struct CadetClient *c = cls;
- stats = GNUNET_STATISTICS_create ("cadet", c);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Open port %s requested by %s\n",
+ GNUNET_h2s (&pmsg->port),
+ GSC_2s (c));
+ if (NULL == c->ports)
+ c->ports = GNUNET_CONTAINER_multihashmap_create (4,
+ GNUNET_NO);
+ if (GNUNET_OK !=
+ GNUNET_CONTAINER_multihashmap_put (c->ports,
+ &pmsg->port,
+ c,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
+ }
+ (void) GNUNET_CONTAINER_multihashmap_put (open_ports,
+ &pmsg->port,
+ c,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+ GNUNET_CONTAINER_multihashmap_get_multiple (loose_channels,
+ &pmsg->port,
+ &bind_loose_channel,
+ c);
+ GNUNET_SERVICE_client_continue (c->client);
+}
- /* Scheduled the task to clean up when shutdown is called */
- GNUNET_SCHEDULER_add_shutdown (&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 */
- GCH_init (c); /* Hellos */
- GCC_init (c); /* Connections */
- GCP_init (c); /* Peers */
- GCD_init (c); /* DHT */
- GCT_init (c, my_private_key); /* Tunnels */
+/**
+ * Handler for port close requests. Marks this port as closed
+ * (unless of course we have another client with the same port
+ * open). Note that existing channels accepted on the port are
+ * not affected.
+ *
+ * @param cls Identification of the client.
+ * @param pmsg The actual message.
+ */
+static void
+handle_port_close (void *cls,
+ const struct GNUNET_CADET_PortMessage *pmsg)
+{
+ struct CadetClient *c = cls;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cadet service running\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Closing port %s as requested by %s\n",
+ GNUNET_h2s (&pmsg->port),
+ GSC_2s (c));
+ if (GNUNET_YES !=
+ GNUNET_CONTAINER_multihashmap_remove (c->ports,
+ &pmsg->port,
+ c))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
+ }
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (open_ports,
+ &pmsg->port,
+ c));
+ GNUNET_SERVICE_client_continue (c->client);
}
/**
- * The main function for the cadet service.
+ * Handler for requests for us creating a new channel to another peer and port.
*
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
+ * @param cls Identification of the client.
+ * @param tcm The actual message.
*/
-int
-main (int argc, char *const *argv)
+static void
+handle_channel_create (void *cls,
+ const struct GNUNET_CADET_LocalChannelCreateMessage *tcm)
{
- int r;
+ struct CadetClient *c = cls;
+ struct CadetChannel *ch;
- shutting_down = GNUNET_NO;
- r = GNUNET_SERVICE_run (argc, argv, "cadet", GNUNET_SERVICE_OPTION_NONE, &run,
- NULL);
- GNUNET_free (my_private_key);
+ if (ntohl (tcm->ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+ {
+ /* Channel ID not in allowed range. */
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
+ }
+ ch = lookup_channel (c,
+ tcm->ccn);
+ if (NULL != ch)
+ {
+ /* Channel ID already in use. Not allowed. */
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "New channel to %s at port %s requested by %s\n",
+ GNUNET_i2s (&tcm->peer),
+ GNUNET_h2s (&tcm->port),
+ GSC_2s (c));
- if (GNUNET_OK != r)
+ /* Create channel */
+ ch = GCCH_channel_local_new (c,
+ tcm->ccn,
+ GCP_get (&tcm->peer,
+ GNUNET_YES),
+ &tcm->port,
+ ntohl (tcm->opt));
+ if (NULL == ch)
{
- FPRINTF (stderr, "GNUNET_SERVICE_run for CADET has failed!\n");
- return 1;
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
}
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap32_put (c->channels,
+ ntohl (tcm->ccn.channel_of_client),
+ ch,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
- return 0;
+ GNUNET_SERVICE_client_continue (c->client);
}
+
+
+/**
+ * Handler for requests of destroying an existing channel.
+ *
+ * @param cls client identification of the client
+ * @param msg the actual message
+ */
+static void
+handle_channel_destroy (void *cls,
+ const struct GNUNET_CADET_LocalChannelDestroyMessage *msg)
+{
+ struct CadetClient *c = cls;
+ struct CadetChannel *ch;
+
+ ch = lookup_channel (c,
+ msg->ccn);
+ if (NULL == ch)
+ {
+ /* Client attempted to destroy unknown channel.
+ Can happen if the other side went down at the same time.*/
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "%s tried to destroy unknown channel %X\n",
+ GSC_2s(c),
+ (uint32_t) ntohl (msg->ccn.channel_of_client));
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "%s is destroying %s\n",
+ GSC_2s(c),
+ GCCH_2s (ch));
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap32_remove (c->channels,
+ ntohl (msg->ccn.channel_of_client),
+ ch));
+ GCCH_channel_local_destroy (ch,
+ c,
+ msg->ccn);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Check for client traffic data message is well-formed.
+ *
+ * @param cls identification of the client
+ * @param msg the actual message
+ * @return #GNUNET_OK if @a msg is OK, #GNUNET_SYSERR if not
+ */
+static int
+check_local_data (void *cls,
+ const struct GNUNET_CADET_LocalData *msg)
+{
+ size_t payload_size;
+ size_t payload_claimed_size;
+ const char *buf;
+ struct GNUNET_MessageHeader pa;
+
+ /* FIXME: what is the format we shall allow for @a msg?
+ ONE payload item or multiple? Seems current cadet_api
+ at least in theory allows more than one. Next-gen
+ cadet_api will likely no more, so we could then
+ simplify this mess again. */
+ /* Sanity check for message size */
+ payload_size = ntohs (msg->header.size) - sizeof (*msg);
+ buf = (const char *) &msg[1];
+ while (payload_size >= sizeof (struct GNUNET_MessageHeader))
+ {
+ /* need to memcpy() for alignment */
+ GNUNET_memcpy (&pa,
+ buf,
+ sizeof (pa));
+ payload_claimed_size = ntohs (pa.size);
+ if ( (payload_size < payload_claimed_size) ||
+ (payload_claimed_size < sizeof (struct GNUNET_MessageHeader)) ||
+ (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_claimed_size) )
+ {
+ GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Local data of %u total size had sub-message %u at %u with %u bytes\n",
+ ntohs (msg->header.size),
+ ntohs (pa.type),
+ (unsigned int) (buf - (const char *) &msg[1]),
+ (unsigned int) payload_claimed_size);
+ return GNUNET_SYSERR;
+ }
+ payload_size -= payload_claimed_size;
+ buf += payload_claimed_size;
+ }
+ if (0 != payload_size)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Handler for client payload traffic to be send on a channel to
+ * another peer.
+ *
+ * @param cls identification of the client
+ * @param msg the actual message
+ */
+static void
+handle_local_data (void *cls,
+ const struct GNUNET_CADET_LocalData *msg)
+{
+ struct CadetClient *c = cls;
+ struct CadetChannel *ch;
+ size_t payload_size;
+ const char *buf;
+
+ ch = lookup_channel (c,
+ msg->ccn);
+ if (NULL == ch)
+ {
+ /* Channel does not exist (anymore) */
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Dropping payload for channel %u from client (channel unknown, other endpoint may have disconnected)\n",
+ (unsigned int) ntohl (msg->ccn.channel_of_client));
+ GNUNET_SERVICE_client_continue (c->client);
+ return;
+ }
+ payload_size = ntohs (msg->header.size) - sizeof (*msg);
+ GNUNET_STATISTICS_update (stats,
+ "# payload received from clients",
+ payload_size,
+ GNUNET_NO);
+ buf = (const char *) &msg[1];
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received %u bytes payload from %s for %s\n",
+ (unsigned int) payload_size,
+ GSC_2s (c),
+ GCCH_2s (ch));
+ if (GNUNET_OK !=
+ GCCH_handle_local_data (ch,
+ msg->ccn,
+ buf,
+ payload_size))
+ {
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
+ }
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Handler for client's ACKs for payload traffic.
+ *
+ * @param cls identification of the client.
+ * @param msg The actual message.
+ */
+static void
+handle_local_ack (void *cls,
+ const struct GNUNET_CADET_LocalAck *msg)
+{
+ struct CadetClient *c = cls;
+ struct CadetChannel *ch;
+
+ ch = lookup_channel (c,
+ msg->ccn);
+ if (NULL == ch)
+ {
+ /* Channel does not exist (anymore) */
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Ignoring local ACK for channel %u from client (channel unknown, other endpoint may have disconnected)\n",
+ (unsigned int) ntohl (msg->ccn.channel_of_client));
+ GNUNET_SERVICE_client_continue (c->client);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Got a local ACK from %s for %s\n",
+ GSC_2s(c),
+ GCCH_2s (ch));
+ GCCH_handle_local_ack (ch,
+ msg->ccn);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * 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 CadetClient *c = cls;
+ struct CadetPeer *p = value;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_CADET_LocalInfoPeer *msg;
+
+ env = GNUNET_MQ_msg (msg,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
+ msg->destination = *peer;
+ msg->paths = htons (GCP_count_paths (p));
+ msg->tunnel = htons (NULL != GCP_get_tunnel (p,
+ GNUNET_NO));
+ GNUNET_MQ_send (c->mq,
+ env);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's INFO PEERS request.
+ *
+ * @param cls Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_get_peers (void *cls,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct CadetClient *c = cls;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_MessageHeader *reply;
+
+ GCP_iterate_all (&get_all_peers_iterator,
+ c);
+ env = GNUNET_MQ_msg (reply,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
+ GNUNET_MQ_send (c->mq,
+ env);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Iterator over all paths of a peer to build an InfoPeer message.
+ * Message contains blocks of peers, first not included.
+ *
+ * @param cls message queue for transmission
+ * @param path Path itself
+ * @param off offset of the peer on @a path
+ * @return #GNUNET_YES if should keep iterating.
+ * #GNUNET_NO otherwise.
+ */
+static int
+path_info_iterator (void *cls,
+ struct CadetPeerPath *path,
+ unsigned int off)
+{
+ struct GNUNET_MQ_Handle *mq = cls;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_MessageHeader *resp;
+ struct GNUNET_PeerIdentity *id;
+ uint16_t path_size;
+ unsigned int i;
+ unsigned int path_length;
+
+ path_length = GCPP_get_length (path);
+ path_size = sizeof (struct GNUNET_PeerIdentity) * (path_length - 1);
+ if (sizeof (*resp) + path_size > UINT16_MAX)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Path of %u entries is too long for info message\n",
+ path_length);
+ return GNUNET_YES;
+ }
+ env = GNUNET_MQ_msg_extra (resp,
+ path_size,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
+ id = (struct GNUNET_PeerIdentity *) &resp[1];
+
+ /* Don't copy first peer. First peer is always the local one. Last
+ * peer is always the destination (leave as 0, EOL).
+ */
+ for (i = 0; i < off; i++)
+ id[i] = *GCP_get_id (GCPP_get_peer_at_offset (path,
+ i + 1));
+ GNUNET_MQ_send (mq,
+ env);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's SHOW_PEER request.
+ *
+ * @param cls Identification of the client.
+ * @param msg The actual message.
+ */
+static void
+handle_show_peer (void *cls,
+ const struct GNUNET_CADET_LocalInfo *msg)
+{
+ struct CadetClient *c = cls;
+ struct CadetPeer *p;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_MessageHeader *resp;
+
+ p = GCP_get (&msg->peer,
+ GNUNET_NO);
+ if (NULL != p)
+ GCP_iterate_paths (p,
+ &path_info_iterator,
+ c->mq);
+ /* Send message with 0/0 to indicate the end */
+ env = GNUNET_MQ_msg (resp,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER_END);
+ GNUNET_MQ_send (c->mq,
+ env);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * 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 a `struct CadetPeer`
+ * @return #GNUNET_YES, to keep iterating.
+ */
+static int
+get_all_tunnels_iterator (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ void *value)
+{
+ struct CadetClient *c = cls;
+ struct CadetPeer *p = value;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_CADET_LocalInfoTunnel *msg;
+ struct CadetTunnel *t;
+
+ t = GCP_get_tunnel (p,
+ GNUNET_NO);
+ if (NULL == t)
+ return GNUNET_YES;
+ env = GNUNET_MQ_msg (msg,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
+ msg->destination = *peer;
+ msg->channels = htonl (GCT_count_channels (t));
+ msg->connections = htonl (GCT_count_any_connections (t));
+ msg->cstate = htons (0);
+ msg->estate = htons ((uint16_t) GCT_get_estate (t));
+ GNUNET_MQ_send (c->mq,
+ env);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS request.
+ *
+ * @param cls client Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_info_tunnels (void *cls,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct CadetClient *c = cls;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_MessageHeader *reply;
+
+ GCP_iterate_all (&get_all_tunnels_iterator,
+ c);
+ env = GNUNET_MQ_msg (reply,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
+ GNUNET_MQ_send (c->mq,
+ env);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Update the message with information about the connection.
+ *
+ * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
+ * @param ct a connection about which we should store information in @a cls
+ */
+static void
+iter_connection (void *cls,
+ struct CadetTConnection *ct)
+{
+ struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
+ struct CadetConnection *cc = ct->cc;
+ struct GNUNET_CADET_ConnectionTunnelIdentifier *h;
+
+ h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
+ h[msg->connections++] = *(GCC_get_id (cc));
+}
+
+
+/**
+ * Update the message with information about the channel.
+ *
+ * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
+ * @param ch a channel about which we should store information in @a cls
+ */
+static void
+iter_channel (void *cls,
+ struct CadetChannel *ch)
+{
+ struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
+ struct GNUNET_CADET_ConnectionTunnelIdentifier *h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
+ struct GNUNET_CADET_ChannelTunnelNumber *chn
+ = (struct GNUNET_CADET_ChannelTunnelNumber *) &h[msg->connections];
+
+ chn[msg->channels++] = GCCH_get_id (ch);
+}
+
+
+/**
+ * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL request.
+ *
+ * @param cls Identification of the client.
+ * @param msg The actual message.
+ */
+static void
+handle_info_tunnel (void *cls,
+ const struct GNUNET_CADET_LocalInfo *msg)
+{
+ struct CadetClient *c = cls;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_CADET_LocalInfoTunnel *resp;
+ struct CadetTunnel *t;
+ struct CadetPeer *p;
+ unsigned int ch_n;
+ unsigned int c_n;
+
+ p = GCP_get (&msg->peer,
+ GNUNET_NO);
+ t = GCP_get_tunnel (p,
+ GNUNET_NO);
+ if (NULL == t)
+ {
+ /* We don't know the tunnel */
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_CADET_LocalInfoTunnel *warn;
+
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Tunnel to %s unknown\n",
+ GNUNET_i2s_full (&msg->peer));
+ env = GNUNET_MQ_msg (warn,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
+ warn->destination = msg->peer;
+ GNUNET_MQ_send (c->mq,
+ env);
+ GNUNET_SERVICE_client_continue (c->client);
+ return;
+ }
+
+ /* Initialize context */
+ ch_n = GCT_count_channels (t);
+ c_n = GCT_count_any_connections (t);
+ env = GNUNET_MQ_msg_extra (resp,
+ c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier) +
+ ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber),
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
+ resp->destination = msg->peer;
+ /* Do not reorder! #iter_channel needs counters in HBO! */
+ GCT_iterate_connections (t,
+ &iter_connection,
+ resp);
+ GCT_iterate_channels (t,
+ &iter_channel,
+ resp);
+ resp->connections = htonl (resp->connections);
+ resp->channels = htonl (resp->channels);
+ resp->cstate = htons (0);
+ resp->estate = htons (GCT_get_estate (t));
+ GNUNET_MQ_send (c->mq,
+ env);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Iterator over all peers to dump info for each peer.
+ *
+ * @param cls Closure (unused).
+ * @param peer Peer ID (tunnel remote peer).
+ * @param value Peer info.
+ *
+ * @return #GNUNET_YES, to keep iterating.
+ */
+static int
+show_peer_iterator (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ void *value)
+{
+ struct CadetPeer *p = value;
+ struct CadetTunnel *t;
+
+ t = GCP_get_tunnel (p,
+ GNUNET_NO);
+ if (NULL != t)
+ GCT_debug (t,
+ GNUNET_ERROR_TYPE_ERROR);
+ LOG (GNUNET_ERROR_TYPE_ERROR, "\n");
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's INFO_DUMP request.
+ *
+ * @param cls Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_info_dump (void *cls,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct CadetClient *c = cls;
+
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Received dump info request from client %u\n",
+ c->id);
+
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "*************************** DUMP START ***************************\n");
+ for (struct CadetClient *ci = clients_head;
+ NULL != ci;
+ ci = ci->next)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "Client %u (%p), handle: %p, ports: %u, channels: %u\n",
+ ci->id,
+ ci,
+ ci->client,
+ (NULL != c->ports)
+ ? GNUNET_CONTAINER_multihashmap_size (ci->ports)
+ : 0,
+ GNUNET_CONTAINER_multihashmap32_size (ci->channels));
+ }
+ LOG (GNUNET_ERROR_TYPE_ERROR, "***************************\n");
+ GCP_iterate_all (&show_peer_iterator,
+ NULL);
+
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "**************************** DUMP END ****************************\n");
+
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+
+/**
+ * Callback called when a client connects to the service.
+ *
+ * @param cls closure for the service
+ * @param client the new client that connected to the service
+ * @param mq the message queue used to send messages to the client
+ * @return @a c
+ */
+static void *
+client_connect_cb (void *cls,
+ struct GNUNET_SERVICE_Client *client,
+ struct GNUNET_MQ_Handle *mq)
+{
+ struct CadetClient *c;
+
+ c = GNUNET_new (struct CadetClient);
+ c->client = client;
+ c->mq = mq;
+ c->id = next_client_id++; /* overflow not important: just for debug */
+ c->channels
+ = GNUNET_CONTAINER_multihashmap32_create (32);
+ GNUNET_CONTAINER_DLL_insert (clients_head,
+ clients_tail,
+ c);
+ GNUNET_STATISTICS_update (stats,
+ "# clients",
+ +1,
+ GNUNET_NO);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "%s connected\n",
+ GSC_2s (c));
+ return c;
+}
+
+
+/**
+ * A channel was destroyed by the other peer. Tell our client.
+ *
+ * @param c client that lost a channel
+ * @param ccn channel identification number for the client
+ * @param ch the channel object
+ */
+void
+GSC_handle_remote_channel_destroy (struct CadetClient *c,
+ struct GNUNET_CADET_ClientChannelNumber ccn,
+ struct CadetChannel *ch)
+{
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_CADET_LocalChannelDestroyMessage *tdm;
+
+ env = GNUNET_MQ_msg (tdm,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
+ tdm->ccn = ccn;
+ GSC_send_to_client (c,
+ env);
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap32_remove (c->channels,
+ ntohl (ccn.channel_of_client),
+ ch));
+}
+
+
+/**
+ * A client that created a loose channel that was not bound to a port
+ * disconnected, drop it from the #loose_channels list.
+ *
+ * @param port the port the channel was trying to bind to
+ * @param ch the channel that was lost
+ */
+void
+GSC_drop_loose_channel (const struct GNUNET_HashCode *port,
+ struct CadetChannel *ch)
+{
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (loose_channels,
+ port,
+ ch));
+}
+
+
+/**
+ * Iterator for deleting each channel whose client endpoint disconnected.
+ *
+ * @param cls Closure (client that has disconnected).
+ * @param key The local channel id in host byte order
+ * @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 CadetClient *c = cls;
+ struct GNUNET_CADET_ClientChannelNumber ccn;
+ struct CadetChannel *ch = value;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Destroying %s, due to %s disconnecting.\n",
+ GCCH_2s (ch),
+ GSC_2s (c));
+ ccn.channel_of_client = htonl (key);
+ GCCH_channel_local_destroy (ch,
+ c,
+ ccn);
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap32_remove (c->channels,
+ key,
+ ch));
+ return GNUNET_OK;
+}
+
+
+/**
+ * Remove client's ports from the global hashmap on disconnect.
+ *
+ * @param cls Closure (unused).
+ * @param key the port.
+ * @param value the `struct CadetClient` to remove
+ * @return #GNUNET_OK, keep iterating.
+ */
+static int
+client_release_ports (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ struct CadetClient *c = value;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Closing port %s due to %s disconnect.\n",
+ GNUNET_h2s (key),
+ GSC_2s (c));
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (open_ports,
+ key,
+ value));
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (c->ports,
+ key,
+ value));
+ return GNUNET_OK;
+}
+
+
+/**
+ * Callback called when a client disconnected from the service
+ *
+ * @param cls closure for the service
+ * @param client the client that disconnected
+ * @param internal_cls should be equal to @a c
+ */
+static void
+client_disconnect_cb (void *cls,
+ struct GNUNET_SERVICE_Client *client,
+ void *internal_cls)
+{
+ struct CadetClient *c = internal_cls;
+
+ GNUNET_assert (c->client == client);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "%s is disconnecting.\n",
+ GSC_2s (c));
+ if (NULL != c->channels)
+ {
+ GNUNET_CONTAINER_multihashmap32_iterate (c->channels,
+ &channel_destroy_iterator,
+ c);
+ GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (c->channels));
+ GNUNET_CONTAINER_multihashmap32_destroy (c->channels);
+ }
+ if (NULL != c->ports)
+ {
+ GNUNET_CONTAINER_multihashmap_iterate (c->ports,
+ &client_release_ports,
+ c);
+ GNUNET_CONTAINER_multihashmap_destroy (c->ports);
+ }
+ GNUNET_CONTAINER_DLL_remove (clients_head,
+ clients_tail,
+ c);
+ GNUNET_STATISTICS_update (stats,
+ "# clients",
+ -1,
+ GNUNET_NO);
+ GNUNET_free (c);
+ if ( (NULL == clients_head) &&
+ (GNUNET_YES == shutting_down) )
+ shutdown_rest ();
+}
+
+
+/**
+ * Setup CADET internals.
+ *
+ * @param cls closure
+ * @param server the initialized server
+ * @param c configuration to use
+ */
+static void
+run (void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *c,
+ struct GNUNET_SERVICE_Handle *service)
+{
+ cfg = c;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (c,
+ "CADET",
+ "RATCHET_MESSAGES",
+ &ratchet_messages))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
+ "CADET",
+ "RATCHET_MESSAGES",
+ "needs to be a number");
+ ratchet_messages = 64;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (c,
+ "CADET",
+ "RATCHET_TIME",
+ &ratchet_time))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
+ "CADET",
+ "RATCHET_TIME",
+ "need delay value");
+ ratchet_time = GNUNET_TIME_UNIT_HOURS;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (c,
+ "CADET",
+ "REFRESH_CONNECTION_TIME",
+ &keepalive_period))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
+ "CADET",
+ "REFRESH_CONNECTION_TIME",
+ "need delay value");
+ keepalive_period = GNUNET_TIME_UNIT_MINUTES;
+ }
+ 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");
+ }
+ my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
+ if (NULL == my_private_key)
+ {
+ GNUNET_break (0);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (my_private_key,
+ &my_full_id.public_key);
+ stats = GNUNET_STATISTICS_create ("cadet",
+ c);
+ GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
+ NULL);
+ ats_ch = GNUNET_ATS_connectivity_init (c);
+ /* FIXME: optimize code to allow GNUNET_YES here! */
+ open_ports = GNUNET_CONTAINER_multihashmap_create (16,
+ GNUNET_NO);
+ loose_channels = GNUNET_CONTAINER_multihashmap_create (16,
+ GNUNET_NO);
+ peers = GNUNET_CONTAINER_multipeermap_create (16,
+ GNUNET_YES);
+ connections = GNUNET_CONTAINER_multishortmap_create (256,
+ GNUNET_YES);
+ GCH_init (c);
+ GCD_init (c);
+ GCO_init (c);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "CADET started for peer %s\n",
+ GNUNET_i2s (&my_full_id));
+
+}
+
+
+/**
+ * Define "main" method using service macro.
+ */
+GNUNET_SERVICE_MAIN
+("cadet",
+ GNUNET_SERVICE_OPTION_NONE,
+ &run,
+ &client_connect_cb,
+ &client_disconnect_cb,
+ NULL,
+ GNUNET_MQ_hd_fixed_size (port_open,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN,
+ struct GNUNET_CADET_PortMessage,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (port_close,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE,
+ struct GNUNET_CADET_PortMessage,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (channel_create,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE,
+ struct GNUNET_CADET_LocalChannelCreateMessage,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (channel_destroy,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY,
+ struct GNUNET_CADET_LocalChannelDestroyMessage,
+ NULL),
+ GNUNET_MQ_hd_var_size (local_data,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
+ struct GNUNET_CADET_LocalData,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (local_ack,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
+ struct GNUNET_CADET_LocalAck,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (get_peers,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
+ struct GNUNET_MessageHeader,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (show_peer,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
+ struct GNUNET_CADET_LocalInfo,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (info_tunnels,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
+ struct GNUNET_MessageHeader,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (info_tunnel,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
+ struct GNUNET_CADET_LocalInfo,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (info_dump,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP,
+ struct GNUNET_MessageHeader,
+ NULL),
+ GNUNET_MQ_handler_end ());
+
+/* end of gnunet-service-cadet-new.c */
diff --git a/src/cadet/gnunet-service-cadet-new.h b/src/cadet/gnunet-service-cadet.h
index bee5c67cc0..2f2d7baf35 100644
--- a/src/cadet/gnunet-service-cadet-new.h
+++ b/src/cadet/gnunet-service-cadet.h
@@ -20,7 +20,7 @@
*/
/**
- * @file cadet/gnunet-service-cadet-new.h
+ * @file cadet/gnunet-service-cadet.h
* @brief Information we track per peer.
* @author Bartlomiej Polot
* @author Christian Grothoff
diff --git a/src/cadet/gnunet-service-cadet_channel.c b/src/cadet/gnunet-service-cadet_channel.c
index 7b7c6e57ce..68e29b66b5 100644
--- a/src/cadet/gnunet-service-cadet_channel.c
+++ b/src/cadet/gnunet-service-cadet_channel.c
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet.
- Copyright (C) 2013 GNUnet e.V.
+ Copyright (C) 2001-2017 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
@@ -17,31 +17,63 @@
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
-
-
+/**
+ * @file cadet/gnunet-service-cadet_channel.c
+ * @brief logical links between CADET clients
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * TODO:
+ * - Congestion/flow control:
+ * + estimate max bandwidth using bursts and use to for CONGESTION CONTROL!
+ * (and figure out how/where to use this!)
+ * + figure out flow control without ACKs (unreliable traffic!)
+ * - revisit handling of 'unbuffered' traffic!
+ * (need to push down through tunnel into connection selection)
+ * - revisit handling of 'buffered' traffic: 4 is a rather small buffer; maybe
+ * reserve more bits in 'options' to allow for buffer size control?
+ */
#include "platform.h"
-#include "gnunet_util_lib.h"
-
+#include "cadet.h"
#include "gnunet_statistics_service.h"
+#include "gnunet-service-cadet_channel.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_tunnels.h"
+#include "gnunet-service-cadet_paths.h"
-#include "cadet.h"
-#include "cadet_protocol.h"
+#define LOG(level,...) GNUNET_log_from (level,"cadet-chn",__VA_ARGS__)
-#include "gnunet-service-cadet_channel.h"
-#include "gnunet-service-cadet_local.h"
-#include "gnunet-service-cadet_tunnel.h"
-#include "gnunet-service-cadet_peer.h"
+/**
+ * How long do we initially wait before retransmitting?
+ */
+#define CADET_INITIAL_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 250)
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-chn",__VA_ARGS__)
-#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-chn",__VA_ARGS__)
+/**
+ * How long do we wait before dropping state about incoming
+ * connection to closed port?
+ */
+#define TIMEOUT_CLOSED_PORT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
-#define CADET_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(\
- GNUNET_TIME_UNIT_MILLISECONDS, 250)
-#define CADET_RETRANSMIT_MARGIN 4
+/**
+ * How long do we wait at least before retransmitting ever?
+ */
+#define MIN_RTT_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 75)
+
+/**
+ * Maximum message ID into the future we accept for out-of-order messages.
+ * If the message is more than this into the future, we drop it. This is
+ * important both to detect values that are actually in the past, as well
+ * as to limit adversarially triggerable memory consumption.
+ *
+ * Note that right now we have "max_pending_messages = 4" hard-coded in
+ * the logic below, so a value of 4 would suffice here. But we plan to
+ * allow larger windows in the future...
+ */
+#define MAX_OUT_OF_ORDER_DISTANCE 1024
/**
- * All the states a connection can be in.
+ * All the states a channel can be in.
*/
enum CadetChannelState
{
@@ -51,9 +83,15 @@ enum CadetChannelState
CADET_CHANNEL_NEW,
/**
- * Connection create message sent, waiting for ACK.
+ * Channel is to a port that is not open, we're waiting for the
+ * port to be opened.
+ */
+ CADET_CHANNEL_LOOSE,
+
+ /**
+ * CHANNEL_OPEN message sent, waiting for CHANNEL_OPEN_ACK.
*/
- CADET_CHANNEL_SENT,
+ CADET_CHANNEL_OPEN_SENT,
/**
* Connection confirmed, ready to carry traffic.
@@ -63,138 +101,144 @@ enum CadetChannelState
/**
- * Info holder for channel messages in queues.
+ * Info needed to retry a message in case it gets lost.
+ * Note that we DO use this structure also for unreliable
+ * messages.
*/
-struct CadetChannelQueue
+struct CadetReliableMessage
{
/**
- * Tunnel Queue.
+ * Double linked list, FIFO style
*/
- struct CadetTunnelQueue *tq;
+ struct CadetReliableMessage *next;
/**
- * Message type (DATA/DATA_ACK)
+ * Double linked list, FIFO style
*/
- uint16_t type;
+ struct CadetReliableMessage *prev;
/**
- * Message copy (for DATAs, to start retransmission timer)
+ * Which channel is this message in?
*/
- struct CadetReliableMessage *copy;
+ struct CadetChannel *ch;
/**
- * Reliability (for DATA_ACKs, to access rel->ack_q)
+ * Entry in the tunnels queue for this message, NULL if it has left
+ * the tunnel. Used to cancel transmission in case we receive an
+ * ACK in time.
*/
- struct CadetChannelReliability *rel;
-};
-
+ struct CadetTunnelQueueEntry *qe;
-/**
- * Info needed to retry a message in case it gets lost.
- */
-struct CadetReliableMessage
-{
/**
- * Double linked list, FIFO style
+ * Data message we are trying to send.
*/
- struct CadetReliableMessage *next;
- struct CadetReliableMessage *prev;
+ struct GNUNET_CADET_ChannelAppDataMessage *data_message;
/**
- * Type of message (payload, channel management).
+ * How soon should we retry if we fail to get an ACK?
+ * Messages in the queue are sorted by this value.
*/
- int16_t type;
+ struct GNUNET_TIME_Absolute next_retry;
/**
- * Tunnel Reliability queue this message is in.
+ * How long do we wait for an ACK after transmission?
+ * Use for the back-off calculation.
*/
- struct CadetChannelReliability *rel;
+ struct GNUNET_TIME_Relative retry_delay;
/**
- * ID of the message (ACK needed to free)
+ * Time when we first successfully transmitted the message
+ * (that is, set @e num_transmissions to 1).
*/
- uint32_t mid;
+ struct GNUNET_TIME_Absolute first_transmission_time;
/**
- * Tunnel Queue.
+ * Identifier of the connection that this message took when it
+ * was first transmitted. Only useful if @e num_transmissions is 1.
*/
- struct CadetChannelQueue *chq;
+ struct GNUNET_CADET_ConnectionTunnelIdentifier connection_taken;
/**
- * When was this message issued (to calculate ACK delay)
+ * How often was this message transmitted? #GNUNET_SYSERR if there
+ * was an error transmitting the message, #GNUNET_NO if it was not
+ * yet transmitted ever, otherwise the number of (re) transmissions.
*/
- struct GNUNET_TIME_Absolute timestamp;
+ int num_transmissions;
- /* struct GNUNET_CADET_ChannelAppDataMessage with payload */
};
/**
- * Info about the traffic state for a client in a channel.
+ * List of received out-of-order data messages.
*/
-struct CadetChannelReliability
+struct CadetOutOfOrderMessage
{
/**
- * Channel this is about.
+ * Double linked list, FIFO style
*/
- struct CadetChannel *ch;
+ struct CadetOutOfOrderMessage *next;
/**
- * DLL of messages sent and not yet ACK'd.
+ * Double linked list, FIFO style
*/
- struct CadetReliableMessage *head_sent;
- struct CadetReliableMessage *tail_sent;
+ struct CadetOutOfOrderMessage *prev;
/**
- * DLL of messages received out of order.
+ * ID of the message (messages up to this point needed
+ * before we give this one to the client).
*/
- struct CadetReliableMessage *head_recv;
- struct CadetReliableMessage *tail_recv;
+ struct ChannelMessageIdentifier mid;
/**
- * Messages received.
+ * The envelope with the payload of the out-of-order message
*/
- unsigned int n_recv;
+ struct GNUNET_MQ_Envelope *env;
- /**
- * Next MID to use for outgoing traffic.
- */
- uint32_t mid_send;
+};
- /**
- * Next MID expected for incoming traffic.
- */
- uint32_t mid_recv;
+/**
+ * Client endpoint of a `struct CadetChannel`. A channel may be a
+ * loopback channel, in which case it has two of these endpoints.
+ * Note that flow control also is required in both directions.
+ */
+struct CadetChannelClient
+{
/**
- * Handle for queued unique data CREATE, DATA_ACK.
+ * Client handle. Not by itself sufficient to designate
+ * the client endpoint, as the same client handle may
+ * be used for both the owner and the destination, and
+ * we thus also need the channel ID to identify the client.
*/
- struct CadetChannelQueue *uniq;
+ struct CadetClient *c;
/**
- * Can we send data to the client?
+ * Head of DLL of messages received out of order or while client was unready.
*/
- int client_ready;
+ struct CadetOutOfOrderMessage *head_recv;
/**
- * Can the client send data to us?
+ * Tail DLL of messages received out of order or while client was unready.
*/
- int client_allowed;
+ struct CadetOutOfOrderMessage *tail_recv;
/**
- * Task to resend/poll in case no ACK is received.
+ * Local tunnel number for this client.
+ * (if owner >= #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI,
+ * otherwise < #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
*/
- struct GNUNET_SCHEDULER_Task * retry_task;
+ struct GNUNET_CADET_ClientChannelNumber ccn;
/**
- * Counter for exponential backoff.
+ * Number of entries currently in @a head_recv DLL.
*/
- struct GNUNET_TIME_Relative retry_timer;
+ unsigned int num_recv;
/**
- * How long does it usually take to get an ACK.
+ * Can we send data to the client?
*/
- struct GNUNET_TIME_Relative expected_delay;
+ int client_ready;
+
};
@@ -209,41 +253,44 @@ struct CadetChannel
struct CadetTunnel *t;
/**
- * Destination port of the channel.
+ * Client owner of the tunnel, if any.
+ * (Used if this channel represends the initiating end of the tunnel.)
*/
- struct GNUNET_HashCode port;
+ struct CadetChannelClient *owner;
/**
- * Global channel number ( < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+ * Client destination of the tunnel, if any.
+ * (Used if this channel represents the listening end of the tunnel.)
*/
- struct GNUNET_CADET_ChannelTunnelNumber gid;
+ struct CadetChannelClient *dest;
/**
- * Local tunnel number for root (owner) client.
- * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI or 0 )
+ * Last entry in the tunnel's queue relating to control messages
+ * (#GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN or
+ * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK). Used to cancel
+ * transmission in case we receive updated information.
*/
- struct GNUNET_CADET_ClientChannelNumber lid_root;
+ struct CadetTunnelQueueEntry *last_control_qe;
/**
- * Local tunnel number for local destination clients (incoming number)
- * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV or 0).
+ * Head of DLL of messages sent and not yet ACK'd.
*/
- struct GNUNET_CADET_ClientChannelNumber lid_dest;
+ struct CadetReliableMessage *head_sent;
/**
- * Channel state.
+ * Tail of DLL of messages sent and not yet ACK'd.
*/
- enum CadetChannelState state;
+ struct CadetReliableMessage *tail_sent;
/**
- * Is the tunnel bufferless (minimum latency)?
+ * Task to resend/poll in case no ACK is received.
*/
- int nobuffer;
+ struct GNUNET_SCHEDULER_Task *retry_control_task;
/**
- * Is the tunnel reliable?
+ * Task to resend/poll in case no ACK is received.
*/
- int reliable;
+ struct GNUNET_SCHEDULER_Task *retry_data_task;
/**
* Last time the channel was used
@@ -251,21 +298,29 @@ struct CadetChannel
struct GNUNET_TIME_Absolute timestamp;
/**
- * Client owner of the tunnel, if any
+ * Destination port of the channel.
*/
- struct CadetClient *root;
+ struct GNUNET_HashCode port;
/**
- * Client destination of the tunnel, if any.
+ * Counter for exponential backoff.
*/
- struct CadetClient *dest;
+ struct GNUNET_TIME_Relative retry_time;
/**
- * Flag to signal the destruction of the channel.
- * If this is set to #GNUNET_YES the channel will be destroyed
- * when the queue is empty.
+ * Bitfield of already-received messages past @e mid_recv.
*/
- int destroy;
+ uint64_t mid_futures;
+
+ /**
+ * Next MID expected for incoming traffic.
+ */
+ struct ChannelMessageIdentifier mid_recv;
+
+ /**
+ * Next MID to use for outgoing traffic.
+ */
+ struct ChannelMessageIdentifier mid_send;
/**
* Total (reliable) messages pending ACK for this channel.
@@ -273,2290 +328,1710 @@ struct CadetChannel
unsigned int pending_messages;
/**
- * Reliability data.
- * Only present (non-NULL) at the owner of a tunnel.
+ * Maximum (reliable) messages pending ACK for this channel
+ * before we throttle the client.
*/
- struct CadetChannelReliability *root_rel;
+ unsigned int max_pending_messages;
/**
- * Reliability data.
- * Only present (non-NULL) at the destination of a tunnel.
+ * Number identifying this channel in its tunnel.
*/
- struct CadetChannelReliability *dest_rel;
+ struct GNUNET_CADET_ChannelTunnelNumber ctn;
-};
+ /**
+ * Channel state.
+ */
+ enum CadetChannelState state;
+ /**
+ * Count how many ACKs we skipped, used to prevent long
+ * sequences of ACK skipping.
+ */
+ unsigned int skip_ack_series;
-/******************************************************************************/
-/******************************* GLOBALS ***********************************/
-/******************************************************************************/
+ /**
+ * Is the tunnel bufferless (minimum latency)?
+ */
+ int nobuffer;
-/**
- * Global handle to the statistics service.
- */
-extern struct GNUNET_STATISTICS_Handle *stats;
+ /**
+ * Is the tunnel reliable?
+ */
+ int reliable;
-/**
- * Local peer own ID (memory efficient handle).
- */
-extern GNUNET_PEER_Id myid;
+ /**
+ * Is the tunnel out-of-order?
+ */
+ int out_of_order;
+ /**
+ * Is this channel a loopback channel, where the destination is us again?
+ */
+ int is_loopback;
-/******************************************************************************/
-/******************************** STATIC ***********************************/
-/******************************************************************************/
+ /**
+ * Flag to signal the destruction of the channel. If this is set to
+ * #GNUNET_YES the channel will be destroyed once the queue is
+ * empty.
+ */
+ int destroy;
+};
-/**
- * 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);
/**
- * send a channel create message.
+ * Get the static string for identification of the channel.
*
- * @param ch Channel for which to send.
- */
-static void
-send_create (struct CadetChannel *ch);
-
-/**
- * Confirm we got a channel create, FWD ack.
+ * @param ch Channel.
*
- * @param ch The channel to confirm.
- * @param fwd Should we send a FWD ACK? (going dest->root)
+ * @return Static string with the channel IDs.
*/
-static void
-send_ack (struct CadetChannel *ch, int fwd);
-
+const char *
+GCCH_2s (const struct CadetChannel *ch)
+{
+ static char buf[128];
+
+ GNUNET_snprintf (buf,
+ sizeof (buf),
+ "Channel %s:%s ctn:%X(%X/%X)",
+ (GNUNET_YES == ch->is_loopback)
+ ? "loopback"
+ : GNUNET_i2s (GCP_get_id (GCT_get_destination (ch->t))),
+ GNUNET_h2s (&ch->port),
+ ch->ctn,
+ (NULL == ch->owner) ? 0 : ntohl (ch->owner->ccn.channel_of_client),
+ (NULL == ch->dest) ? 0 : ntohl (ch->dest->ccn.channel_of_client));
+ return buf;
+}
/**
- * Test if the channel is loopback: both root and dest are on the local peer.
+ * Get the channel's public ID.
*
- * @param ch Channel to test.
+ * @param ch Channel.
*
- * @return #GNUNET_YES if channel is loopback, #GNUNET_NO otherwise.
+ * @return ID used to identify the channel with the remote peer.
*/
-static int
-is_loopback (const struct CadetChannel *ch)
+struct GNUNET_CADET_ChannelTunnelNumber
+GCCH_get_id (const struct CadetChannel *ch)
{
- if (NULL != ch->t)
- return GCT_is_loopback (ch->t);
-
- return (NULL != ch->root && NULL != ch->dest);
+ return ch->ctn;
}
/**
- * Save a copy of the data message for later retransmission.
+ * Release memory associated with @a ccc
*
- * @param msg Message to copy.
- * @param mid Message ID.
- * @param rel Reliability data for retransmission.
+ * @param ccc data structure to clean up
*/
-static struct CadetReliableMessage *
-copy_message (const struct GNUNET_CADET_ChannelAppDataMessage *msg, uint32_t mid,
- struct CadetChannelReliability *rel)
+static void
+free_channel_client (struct CadetChannelClient *ccc)
{
- struct CadetReliableMessage *copy;
- uint16_t size;
+ struct CadetOutOfOrderMessage *com;
- size = ntohs (msg->header.size);
- copy = GNUNET_malloc (sizeof (*copy) + size);
- copy->mid = mid;
- copy->rel = rel;
- copy->type = GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA;
- GNUNET_memcpy (&copy[1], msg, size);
-
- return copy;
+ while (NULL != (com = ccc->head_recv))
+ {
+ GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
+ ccc->tail_recv,
+ com);
+ ccc->num_recv--;
+ GNUNET_MQ_discard (com->env);
+ GNUNET_free (com);
+ }
+ GNUNET_free (ccc);
}
+
/**
- * 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.
+ * Destroy the given channel.
*
- * @param msg Message to buffer (MUST be of type CADET_DATA).
- * @param rel Reliability data to the corresponding direction.
+ * @param ch channel to destroy
*/
static void
-add_buffered_data (const struct GNUNET_CADET_ChannelAppDataMessage *msg,
- struct CadetChannelReliability *rel)
+channel_destroy (struct CadetChannel *ch)
{
- struct CadetReliableMessage *copy;
- struct CadetReliableMessage *prev;
- uint32_t mid;
-
- mid = ntohl (msg->mid);
+ struct CadetReliableMessage *crm;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data MID %u (%u)\n",
- mid, rel->n_recv);
-
- 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)
+ while (NULL != (crm = ch->head_sent))
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " prev %u\n", prev->mid);
- if (prev->mid == mid)
+ GNUNET_assert (ch == crm->ch);
+ if (NULL != crm->qe)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " already there!\n");
- rel->n_recv--;
- return;
- }
- else if (GC_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;
+ GCT_send_cancel (crm->qe);
+ crm->qe = NULL;
}
+ GNUNET_CONTAINER_DLL_remove (ch->head_sent,
+ ch->tail_sent,
+ crm);
+ GNUNET_free (crm->data_message);
+ GNUNET_free (crm);
+ }
+ if (NULL != ch->owner)
+ {
+ free_channel_client (ch->owner);
+ ch->owner = NULL;
}
- copy = copy_message (msg, mid, rel);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " insert at tail! (now: %u)\n", rel->n_recv);
- GNUNET_CONTAINER_DLL_insert_tail (rel->head_recv, rel->tail_recv, copy);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data END\n");
+ if (NULL != ch->dest)
+ {
+ free_channel_client (ch->dest);
+ ch->dest = NULL;
+ }
+ if (NULL != ch->last_control_qe)
+ {
+ GCT_send_cancel (ch->last_control_qe);
+ ch->last_control_qe = NULL;
+ }
+ if (NULL != ch->retry_data_task)
+ {
+ GNUNET_SCHEDULER_cancel (ch->retry_data_task);
+ ch->retry_data_task = NULL;
+ }
+ if (NULL != ch->retry_control_task)
+ {
+ GNUNET_SCHEDULER_cancel (ch->retry_control_task);
+ ch->retry_control_task = NULL;
+ }
+ if (GNUNET_NO == ch->is_loopback)
+ {
+ GCT_remove_channel (ch->t,
+ ch,
+ ch->ctn);
+ ch->t = NULL;
+ }
+ GNUNET_free (ch);
}
/**
- * Add a destination client to a channel, initializing all data structures
- * in the channel and the client.
+ * Send a channel create message.
*
- * @param ch Channel to which add the destination.
- * @param c Client which to add to the channel.
+ * @param cls Channel for which to send.
*/
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_ccn (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;
-}
+send_channel_open (void *cls);
/**
- * Set options in a channel, extracted from a bit flag field.
+ * Function called once the tunnel confirms that we sent the
+ * create message. Delays for a bit until we retry.
*
- * @param ch Channel to set options to.
- * @param options Bit array in host byte order.
+ * @param cls our `struct CadetChannel`.
+ * @param cid identifier of the connection within the tunnel, NULL
+ * if transmission failed
*/
static void
-channel_set_options (struct CadetChannel *ch, uint32_t options)
+channel_open_sent_cb (void *cls,
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
{
- ch->nobuffer = (options & GNUNET_CADET_OPTION_NOBUFFER) != 0 ?
- GNUNET_YES : GNUNET_NO;
- ch->reliable = (options & GNUNET_CADET_OPTION_RELIABLE) != 0 ?
- GNUNET_YES : GNUNET_NO;
+ struct CadetChannel *ch = cls;
+
+ GNUNET_assert (NULL != ch->last_control_qe);
+ ch->last_control_qe = NULL;
+ ch->retry_time = GNUNET_TIME_STD_BACKOFF (ch->retry_time);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sent CADET_CHANNEL_OPEN on %s, retrying in %s\n",
+ GCCH_2s (ch),
+ GNUNET_STRINGS_relative_time_to_string (ch->retry_time,
+ GNUNET_YES));
+ ch->retry_control_task
+ = GNUNET_SCHEDULER_add_delayed (ch->retry_time,
+ &send_channel_open,
+ ch);
}
/**
- * Get a bit flag field with the options of a channel.
+ * Send a channel open message.
*
- * @param ch Channel to get options from.
- *
- * @return Bit array in host byte order.
+ * @param cls Channel for which to send.
*/
-static uint32_t
-channel_get_options (struct CadetChannel *ch)
+static void
+send_channel_open (void *cls)
{
+ struct CadetChannel *ch = cls;
+ struct GNUNET_CADET_ChannelOpenMessage msgcc;
uint32_t options;
+ ch->retry_control_task = NULL;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending CHANNEL_OPEN message for %s\n",
+ GCCH_2s (ch));
options = 0;
if (ch->nobuffer)
options |= GNUNET_CADET_OPTION_NOBUFFER;
if (ch->reliable)
options |= GNUNET_CADET_OPTION_RELIABLE;
-
- return options;
+ if (ch->out_of_order)
+ options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
+ msgcc.header.size = htons (sizeof (msgcc));
+ msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN);
+ msgcc.opt = htonl (options);
+ msgcc.port = ch->port;
+ msgcc.ctn = ch->ctn;
+ ch->state = CADET_CHANNEL_OPEN_SENT;
+ if (NULL != ch->last_control_qe)
+ GCT_send_cancel (ch->last_control_qe);
+ ch->last_control_qe = GCT_send (ch->t,
+ &msgcc.header,
+ &channel_open_sent_cb,
+ ch);
+ GNUNET_assert (NULL == ch->retry_control_task);
}
/**
- * 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?
+ * Function called once and only once after a channel was bound
+ * to its tunnel via #GCT_add_channel() is ready for transmission.
+ * Note that this is only the case for channels that this peer
+ * initiates, as for incoming channels we assume that they are
+ * ready for transmission immediately upon receiving the open
+ * message. Used to bootstrap the #GCT_send() process.
+ *
+ * @param ch the channel for which the tunnel is now ready
*/
-static void
-send_destroy (struct CadetChannel *ch, int local_only)
+void
+GCCH_tunnel_up (struct CadetChannel *ch)
{
- struct GNUNET_CADET_ChannelManageMessage msg;
-
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
- msg.header.size = htons (sizeof (msg));
- msg.ctn = 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.channel_of_client && GNUNET_NO == local_only)
- GCCH_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.channel_of_client && GNUNET_NO == local_only)
- GCCH_send_prebuilt_message (&msg.header, ch, GNUNET_YES, NULL);
+ GNUNET_assert (NULL == ch->retry_control_task);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Tunnel up, sending CHANNEL_OPEN on %s now\n",
+ GCCH_2s (ch));
+ ch->retry_control_task
+ = GNUNET_SCHEDULER_add_now (&send_channel_open,
+ ch);
}
/**
- * Notify the destination client that a new incoming channel was created.
+ * Create a new channel.
*
- * @param ch Channel that was created.
+ * @param owner local client owning the channel
+ * @param ccn local number of this channel at the @a owner
+ * @param destination peer to which we should build the channel
+ * @param port desired port at @a destination
+ * @param options options for the channel
+ * @return handle to the new channel
*/
-static void
-send_client_create (struct CadetChannel *ch)
+struct CadetChannel *
+GCCH_channel_local_new (struct CadetClient *owner,
+ struct GNUNET_CADET_ClientChannelNumber ccn,
+ struct CadetPeer *destination,
+ const struct GNUNET_HashCode *port,
+ uint32_t options)
{
- 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,
- GCT_get_destination (ch->t));
-
-}
+ struct CadetChannel *ch;
+ struct CadetChannelClient *ccco;
+ ccco = GNUNET_new (struct CadetChannelClient);
+ ccco->c = owner;
+ ccco->ccn = ccn;
+ ccco->client_ready = GNUNET_YES;
-/**
- * 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_ChannelAppDataMessage *msg,
- int fwd)
-{
- if (fwd)
- {
- if (ch->dest_rel->client_ready)
+ ch = GNUNET_new (struct CadetChannel);
+ ch->mid_recv.mid = htonl (1); /* The OPEN_ACK counts as message 0! */
+ ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
+ ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
+ ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
+ ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
+ ch->owner = ccco;
+ ch->port = *port;
+ if (0 == memcmp (&my_full_id,
+ GCP_get_id (destination),
+ sizeof (struct GNUNET_PeerIdentity)))
+ {
+ struct CadetClient *c;
+
+ ch->is_loopback = GNUNET_YES;
+ c = GNUNET_CONTAINER_multihashmap_get (open_ports,
+ port);
+ if (NULL == c)
{
- GML_send_data (ch->dest, msg, ch->lid_dest);
- ch->dest_rel->client_ready = GNUNET_NO;
- ch->dest_rel->mid_recv++;
+ /* port closed, wait for it to possibly open */
+ ch->state = CADET_CHANNEL_LOOSE;
+ (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
+ port,
+ ch,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Created loose incoming loopback channel to port %s\n",
+ GNUNET_h2s (&ch->port));
}
else
- add_buffered_data (msg, ch->dest_rel);
+ {
+ GCCH_bind (ch,
+ c);
+ }
}
else
{
- if (ch->root_rel->client_ready)
- {
- GML_send_data (ch->root, msg, ch->lid_root);
- ch->root_rel->client_ready = GNUNET_NO;
- ch->root_rel->mid_recv++;
- }
- else
- add_buffered_data (msg, ch->root_rel);
+ ch->t = GCP_get_tunnel (destination,
+ GNUNET_YES);
+ ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
+ ch->ctn = GCT_add_channel (ch->t,
+ ch);
}
+ GNUNET_STATISTICS_update (stats,
+ "# channels",
+ 1,
+ GNUNET_NO);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Created channel to port %s at peer %s for %s using %s\n",
+ GNUNET_h2s (port),
+ GCP_2s (destination),
+ GSC_2s (owner),
+ (GNUNET_YES == ch->is_loopback) ? "loopback" : GCT_2s (ch->t));
+ return ch;
}
/**
- * Send a buffered message to the client, for in order delivery or
- * as result of client ACK.
+ * We had an incoming channel to a port that is closed.
+ * It has not been opened for a while, drop it.
*
- * @param ch Channel on which to empty the message buffer.
- * @param c Client to send to.
- * @param fwd Is this to send FWD data?.
+ * @param cls the channel to drop
*/
static void
-send_client_buffered_data (struct CadetChannel *ch,
- struct CadetClient *c,
- int fwd)
+timeout_closed_cb (void *cls)
{
- 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;
- }
+ struct CadetChannel *ch = cls;
- 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_ChannelAppDataMessage *msg = (struct GNUNET_CADET_ChannelAppDataMessage *) &copy[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--;
- GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " free copy recv MID %u (%p), %u left\n",
- copy->mid, copy, rel->n_recv);
- GNUNET_free (copy);
- GCCH_send_data_ack (ch, fwd);
- }
- 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);
- GCCH_destroy (ch);
- }
- }
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data END\n");
+ ch->retry_control_task = NULL;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Closing incoming channel to port %s from peer %s due to timeout\n",
+ GNUNET_h2s (&ch->port),
+ GCP_2s (GCT_get_destination (ch->t)));
+ channel_destroy (ch);
}
/**
- * Allow a client to send more data.
- *
- * In case the client was already allowed to send data, do nothing.
+ * Create a new channel based on a request coming in over the network.
*
- * @param ch Channel.
- * @param fwd Is this a FWD ACK? (FWD ACKs are sent to root)
+ * @param t tunnel to the remote peer
+ * @param ctn identifier of this channel in the tunnel
+ * @param port desired local port
+ * @param options options for the channel
+ * @return handle to the new channel
*/
-static void
-send_client_ack (struct CadetChannel *ch, int fwd)
+struct CadetChannel *
+GCCH_channel_incoming_new (struct CadetTunnel *t,
+ struct GNUNET_CADET_ChannelTunnelNumber ctn,
+ const struct GNUNET_HashCode *port,
+ uint32_t options)
{
- struct CadetChannelReliability *rel = fwd ? ch->root_rel : ch->dest_rel;
- struct CadetClient *c = fwd ? ch->root : ch->dest;
+ struct CadetChannel *ch;
+ struct CadetClient *c;
+
+ ch = GNUNET_new (struct CadetChannel);
+ ch->port = *port;
+ ch->t = t;
+ ch->ctn = ctn;
+ ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
+ ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
+ ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
+ ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
+ ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
+ GNUNET_STATISTICS_update (stats,
+ "# channels",
+ 1,
+ GNUNET_NO);
+ c = GNUNET_CONTAINER_multihashmap_get (open_ports,
+ port);
if (NULL == c)
{
- GNUNET_break (GNUNET_NO != ch->destroy);
- return;
+ /* port closed, wait for it to possibly open */
+ ch->state = CADET_CHANNEL_LOOSE;
+ (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
+ port,
+ ch,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+ GNUNET_assert (NULL == ch->retry_control_task);
+ ch->retry_control_task
+ = GNUNET_SCHEDULER_add_delayed (TIMEOUT_CLOSED_PORT,
+ &timeout_closed_cb,
+ ch);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Created loose incoming channel to port %s from peer %s\n",
+ GNUNET_h2s (&ch->port),
+ GCP_2s (GCT_get_destination (ch->t)));
}
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " sending %s ack to client on channel %s\n",
- GC_f2s (fwd), GCCH_2s (ch));
-
- if (NULL == rel)
+ else
{
- GNUNET_break (0);
- return;
+ GCCH_bind (ch,
+ c);
}
-
- 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);
+ GNUNET_STATISTICS_update (stats,
+ "# channels",
+ 1,
+ GNUNET_NO);
+ return ch;
}
/**
- * Notify the root that the destination rejected the channel.
+ * Function called once the tunnel confirms that we sent the
+ * ACK message. Just remembers it was sent, we do not expect
+ * ACKs for ACKs ;-).
*
- * @param ch Rejected channel.
+ * @param cls our `struct CadetChannel`.
+ * @param cid identifier of the connection within the tunnel, NULL
+ * if transmission failed
*/
static void
-send_client_nack (struct CadetChannel *ch)
+send_ack_cb (void *cls,
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
{
- if (NULL == ch->root)
- {
- GNUNET_break (0);
- return;
- }
- GML_send_channel_nack (ch->root, ch->lid_root);
+ struct CadetChannel *ch = cls;
+
+ GNUNET_assert (NULL != ch->last_control_qe);
+ ch->last_control_qe = NULL;
}
/**
- * We haven't received an ACK after a certain time: restransmit the message.
+ * Compute and send the current #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK to the other peer.
*
- * @param cls Closure (CadetChannelReliability with the message to restransmit)
+ * @param ch channel to send the #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK for
*/
static void
-channel_retransmit_message (void *cls)
+send_channel_data_ack (struct CadetChannel *ch)
{
- struct CadetChannelReliability *rel = cls;
- struct CadetReliableMessage *copy;
- struct CadetChannel *ch;
- struct GNUNET_CADET_ChannelAppDataMessage *payload;
- int fwd;
-
- rel->retry_task = NULL;
- ch = rel->ch;
- copy = rel->head_sent;
- if (NULL == copy)
- {
- GNUNET_break (0); // FIXME tripped in rps testcase
- return;
- }
-
- payload = (struct GNUNET_CADET_ChannelAppDataMessage *) &copy[1];
- fwd = (rel == ch->root_rel);
-
- /* Message not found in the queue that we are going to use. */
- LOG (GNUNET_ERROR_TYPE_DEBUG, "RETRANSMIT MID %u\n", copy->mid);
+ struct GNUNET_CADET_ChannelDataAckMessage msg;
- GCCH_send_prebuilt_message (&payload->header, ch, fwd, copy);
- GNUNET_STATISTICS_update (stats, "# data retransmitted", 1, GNUNET_NO);
+ if (GNUNET_NO == ch->reliable)
+ return; /* no ACKs */
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK);
+ msg.header.size = htons (sizeof (msg));
+ msg.ctn = ch->ctn;
+ msg.mid.mid = htonl (ntohl (ch->mid_recv.mid));
+ msg.futures = GNUNET_htonll (ch->mid_futures);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending DATA_ACK %u:%llX via %s\n",
+ (unsigned int) ntohl (msg.mid.mid),
+ (unsigned long long) ch->mid_futures,
+ GCCH_2s (ch));
+ if (NULL != ch->last_control_qe)
+ GCT_send_cancel (ch->last_control_qe);
+ ch->last_control_qe = GCT_send (ch->t,
+ &msg.header,
+ &send_ack_cb,
+ ch);
}
/**
- * We haven't received an Channel ACK after a certain time: resend the CREATE.
+ * Send our initial #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK to the client confirming that the
+ * connection is up.
*
- * @param cls Closure (CadetChannelReliability of the channel to recreate)
+ * @param cls the `struct CadetChannel`
*/
static void
-channel_recreate (void *cls)
+send_open_ack (void *cls)
{
- struct CadetChannelReliability *rel = cls;
-
- rel->retry_task = NULL;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "RE-CREATE\n");
- GNUNET_STATISTICS_update (stats,
- "# data retransmitted", 1, GNUNET_NO);
+ struct CadetChannel *ch = cls;
+ struct GNUNET_CADET_ChannelManageMessage msg;
- if (rel == rel->ch->root_rel)
- {
- send_create (rel->ch);
- }
- else if (rel == rel->ch->dest_rel)
- {
- send_ack (rel->ch, GNUNET_YES);
- }
- else
- {
- GNUNET_break (0);
- }
+ ch->retry_control_task = NULL;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending CHANNEL_OPEN_ACK on %s\n",
+ GCCH_2s (ch));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK);
+ msg.header.size = htons (sizeof (msg));
+ msg.reserved = htonl (0);
+ msg.ctn = ch->ctn;
+ if (NULL != ch->last_control_qe)
+ GCT_send_cancel (ch->last_control_qe);
+ ch->last_control_qe = GCT_send (ch->t,
+ &msg.header,
+ &send_ack_cb,
+ ch);
}
/**
- * Message has been sent: start retransmission timer.
+ * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
+ * this channel. If the binding was successful, (re)transmit the
+ * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
*
- * @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.
+ * @param ch channel that got the duplicate open
+ * @param cti identifier of the connection that delivered the message
*/
-static void
-ch_message_sent (void *cls,
- struct CadetTunnel *t,
- struct CadetTunnelQueue *q,
- uint16_t type, size_t size)
+void
+GCCH_handle_duplicate_open (struct CadetChannel *ch,
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
{
- struct CadetChannelQueue *chq = cls;
- struct CadetReliableMessage *copy = chq->copy;
- struct CadetChannelReliability *rel;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "channel_message_sent callback %s\n",
- GC_m2s (chq->type));
-
- switch (chq->type)
+ if (NULL == ch->dest)
{
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA:
- LOG (GNUNET_ERROR_TYPE_DEBUG, "data MID %u sent\n", copy->mid);
- GNUNET_assert (chq == copy->chq);
- copy->timestamp = GNUNET_TIME_absolute_get ();
- rel = copy->rel;
- if (NULL == rel->retry_task)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " scheduling retry in %d * %s\n",
- CADET_RETRANSMIT_MARGIN,
- GNUNET_STRINGS_relative_time_to_string (rel->expected_delay,
- GNUNET_YES));
- if (0 != rel->expected_delay.rel_value_us)
- {
- rel->retry_timer =
- GNUNET_TIME_relative_saturating_multiply (rel->expected_delay,
- CADET_RETRANSMIT_MARGIN);
- }
- else
- {
- 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 running %p\n", rel->retry_task);
- }
- copy->chq = NULL;
- break;
-
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK:
- LOG (GNUNET_ERROR_TYPE_DEBUG, "sent %s\n", GC_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_CHANNEL_APP_DATA_ACK != type
- && GNUNET_NO == rel->ch->destroy)
- {
- GNUNET_assert (NULL == 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);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Ignoring duplicate CHANNEL_OPEN on %s: port is closed\n",
+ GCCH_2s (ch));
+ return;
}
-
- GNUNET_free (chq);
+ if (NULL != ch->retry_control_task)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Ignoring duplicate CHANNEL_OPEN on %s: control message is pending\n",
+ GCCH_2s (ch));
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Retransmitting CHANNEL_OPEN_ACK on %s\n",
+ GCCH_2s (ch));
+ ch->retry_control_task
+ = GNUNET_SCHEDULER_add_now (&send_open_ack,
+ ch);
}
/**
- * send a channel create message.
+ * Send a #GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK to the client to solicit more messages.
*
- * @param ch Channel for which to send.
+ * @param ch channel the ack is for
+ * @param to_owner #GNUNET_YES to send to owner,
+ * #GNUNET_NO to send to dest
*/
static void
-send_create (struct CadetChannel *ch)
+send_ack_to_client (struct CadetChannel *ch,
+ int to_owner)
{
- struct GNUNET_CADET_ChannelOpenMessage msgcc;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_CADET_LocalAck *ack;
+ struct CadetChannelClient *ccc;
- msgcc.header.size = htons (sizeof (msgcc));
- msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN);
- msgcc.ctn = ch->gid;
- msgcc.port = ch->port;
- msgcc.opt = htonl (channel_get_options (ch));
-
- GCCH_send_prebuilt_message (&msgcc.header, ch, GNUNET_YES, NULL);
+ ccc = (GNUNET_YES == to_owner) ? ch->owner : ch->dest;
+ if (NULL == ccc)
+ {
+ /* This can happen if we are just getting ACKs after
+ our local client already disconnected. */
+ GNUNET_assert (GNUNET_YES == ch->destroy);
+ return;
+ }
+ env = GNUNET_MQ_msg (ack,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
+ ack->ccn = ccc->ccn;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending CADET_LOCAL_ACK to %s (%s) at ccn %X (%u/%u pending)\n",
+ GSC_2s (ccc->c),
+ (GNUNET_YES == to_owner) ? "owner" : "dest",
+ ntohl (ack->ccn.channel_of_client),
+ ch->pending_messages,
+ ch->max_pending_messages);
+ GSC_send_to_client (ccc->c,
+ env);
}
/**
- * Confirm we got a channel create or FWD ack.
+ * A client is bound to the port that we have a channel
+ * open to. Send the acknowledgement for the connection
+ * request and establish the link with the client.
*
- * @param ch The channel to confirm.
- * @param fwd Should we send a FWD ACK? (going dest->root)
+ * @param ch open incoming channel
+ * @param c client listening on the respective port
*/
-static void
-send_ack (struct CadetChannel *ch, int fwd)
+void
+GCCH_bind (struct CadetChannel *ch,
+ struct CadetClient *c)
{
- struct GNUNET_CADET_ChannelManageMessage msg;
+ uint32_t options;
+ struct CadetChannelClient *cccd;
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK);
LOG (GNUNET_ERROR_TYPE_DEBUG,
- " sending channel %s ack for channel %s\n",
- GC_f2s (fwd), GCCH_2s (ch));
-
- msg.ctn =ch->gid;
- GCCH_send_prebuilt_message (&msg.header, ch, !fwd, NULL);
+ "Binding %s from %s to port %s of %s\n",
+ GCCH_2s (ch),
+ GCT_2s (ch->t),
+ GNUNET_h2s (&ch->port),
+ GSC_2s (c));
+ if (NULL != ch->retry_control_task)
+ {
+ /* there might be a timeout task here */
+ GNUNET_SCHEDULER_cancel (ch->retry_control_task);
+ ch->retry_control_task = NULL;
+ }
+ options = 0;
+ if (ch->nobuffer)
+ options |= GNUNET_CADET_OPTION_NOBUFFER;
+ if (ch->reliable)
+ options |= GNUNET_CADET_OPTION_RELIABLE;
+ if (ch->out_of_order)
+ options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
+ cccd = GNUNET_new (struct CadetChannelClient);
+ GNUNET_assert (NULL == ch->dest);
+ ch->dest = cccd;
+ cccd->c = c;
+ cccd->client_ready = GNUNET_YES;
+ cccd->ccn = GSC_bind (c,
+ ch,
+ (GNUNET_YES == ch->is_loopback)
+ ? GCP_get (&my_full_id,
+ GNUNET_YES)
+ : GCT_get_destination (ch->t),
+ &ch->port,
+ options);
+ GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
+ GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
+ ch->mid_recv.mid = htonl (1); /* The OPEN counts as message 0! */
+ if (GNUNET_YES == ch->is_loopback)
+ {
+ ch->state = CADET_CHANNEL_OPEN_SENT;
+ GCCH_handle_channel_open_ack (ch,
+ NULL);
+ }
+ else
+ {
+ /* notify other peer that we accepted the connection */
+ ch->state = CADET_CHANNEL_READY;
+ ch->retry_control_task
+ = GNUNET_SCHEDULER_add_now (&send_open_ack,
+ ch);
+ }
+ /* give client it's initial supply of ACKs */
+ GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
+ GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
+ for (unsigned int i=0;i<ch->max_pending_messages;i++)
+ send_ack_to_client (ch,
+ GNUNET_NO);
}
/**
- * Send a message and don't keep any info about it: we won't need to cancel it
- * or resend it.
+ * One of our clients has disconnected, tell the other one that we
+ * are finished. Done asynchronously to avoid concurrent modification
+ * issues if this is the same client.
*
- * @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?
+ * @param cls the `struct CadetChannel` where one of the ends is now dead
*/
static void
-fire_and_forget (const struct GNUNET_MessageHeader *msg,
- struct CadetChannel *ch,
- int force)
+signal_remote_destroy_cb (void *cls)
{
- GNUNET_break (NULL ==
- GCT_send_prebuilt_message (msg, ch->t, NULL,
- force, NULL, NULL));
+ struct CadetChannel *ch = cls;
+ struct CadetChannelClient *ccc;
+
+ /* Find which end is left... */
+ ch->retry_control_task = NULL;
+ ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
+ GSC_handle_remote_channel_destroy (ccc->c,
+ ccc->ccn,
+ ch);
+ channel_destroy (ch);
}
/**
- * Notify that a channel create didn't succeed.
+ * Destroy locally created channel. Called by the local client, so no
+ * need to tell the client.
*
- * @param ch The channel to reject.
+ * @param ch channel to destroy
+ * @param c client that caused the destruction
+ * @param ccn client number of the client @a c
*/
-static void
-send_nack (struct CadetChannel *ch)
+void
+GCCH_channel_local_destroy (struct CadetChannel *ch,
+ struct CadetClient *c,
+ struct GNUNET_CADET_ClientChannelNumber ccn)
{
- struct GNUNET_CADET_ChannelManageMessage msg;
-
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED);
LOG (GNUNET_ERROR_TYPE_DEBUG,
- " sending channel NACK for channel %s\n",
+ "%s asks for destruction of %s\n",
+ GSC_2s (c),
GCCH_2s (ch));
+ GNUNET_assert (NULL != c);
+ if ( (NULL != ch->owner) &&
+ (c == ch->owner->c) &&
+ (ccn.channel_of_client == ch->owner->ccn.channel_of_client) )
+ {
+ free_channel_client (ch->owner);
+ ch->owner = NULL;
+ }
+ else if ( (NULL != ch->dest) &&
+ (c == ch->dest->c) &&
+ (ccn.channel_of_client == ch->dest->ccn.channel_of_client) )
+ {
+ free_channel_client (ch->dest);
+ ch->dest = NULL;
+ }
+ else
+ {
+ GNUNET_assert (0);
+ }
- msg.ctn = ch->gid;
- GCCH_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)
+ if (GNUNET_YES == ch->destroy)
{
- next = copy->next;
- GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE ALL RECV %p\n", copy);
- GNUNET_break (NULL == copy->chq);
- GNUNET_free (copy);
+ /* other end already destroyed, with the local client gone, no need
+ to finish transmissions, just destroy immediately. */
+ channel_destroy (ch);
+ return;
}
- for (copy = rel->head_sent; NULL != copy; copy = next)
+ if ( (NULL != ch->head_sent) &&
+ ( (NULL != ch->owner) ||
+ (NULL != ch->dest) ) )
{
- next = copy->next;
- GNUNET_CONTAINER_DLL_remove (rel->head_sent, rel->tail_sent, copy);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE ALL SEND %p\n", copy);
- if (NULL != copy->chq)
- {
- if (NULL != copy->chq->tq)
- {
- GCT_cancel (copy->chq->tq);
- /* ch_message_sent will free copy->q */
- }
- else
- {
- GNUNET_free (copy->chq);
- GNUNET_break (0);
- }
- }
- GNUNET_free (copy);
+ /* Wait for other end to destroy us as well,
+ and otherwise allow send queue to be transmitted first */
+ ch->destroy = GNUNET_YES;
+ return;
}
- if (NULL != rel->uniq && NULL != rel->uniq->tq)
+ if ( (GNUNET_YES == ch->is_loopback) &&
+ ( (NULL != ch->owner) ||
+ (NULL != ch->dest) ) )
{
- GCT_cancel (rel->uniq->tq);
- /* ch_message_sent is called freeing uniq */
+ if (NULL != ch->retry_control_task)
+ GNUNET_SCHEDULER_cancel (ch->retry_control_task);
+ ch->retry_control_task
+ = GNUNET_SCHEDULER_add_now (&signal_remote_destroy_cb,
+ ch);
+ return;
}
- if (NULL != rel->retry_task)
+ if (GNUNET_NO == ch->is_loopback)
{
- GNUNET_SCHEDULER_cancel (rel->retry_task);
- rel->retry_task = NULL;
+ /* If the we ever sent the CHANNEL_CREATE, we need to send a destroy message. */
+ switch (ch->state)
+ {
+ case CADET_CHANNEL_NEW:
+ /* We gave up on a channel that we created as a client to a remote
+ target, but that never went anywhere. Nothing to do here. */
+ break;
+ case CADET_CHANNEL_LOOSE:
+ GSC_drop_loose_channel (&ch->port,
+ ch);
+ break;
+ default:
+ GCT_send_channel_destroy (ch->t,
+ ch->ctn);
+ }
}
- GNUNET_free (rel);
+ /* Nothing left to do, just finish destruction */
+ channel_destroy (ch);
}
/**
- * Mark future messages as ACK'd.
- *
- * @param rel Reliability data.
- * @param msg DataACK message with a bitfield of future ACK'd messages.
+ * We got an acknowledgement for the creation of the channel
+ * (the port is open on the other side). Begin transmissions.
*
- * @return How many messages have been freed.
+ * @param ch channel to destroy
+ * @param cti identifier of the connection that delivered the message
*/
-static unsigned int
-channel_rel_free_sent (struct CadetChannelReliability *rel,
- const struct GNUNET_CADET_ChannelDataAckMessage *msg)
+void
+GCCH_handle_channel_open_ack (struct CadetChannel *ch,
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
{
- struct CadetReliableMessage *copy;
- struct CadetReliableMessage *next;
- uint64_t bitfield;
- uint64_t mask;
- uint32_t mid;
- uint32_t target;
- unsigned int i;
- unsigned int r;
-
- bitfield = msg->futures;
- mid = ntohl (msg->mid);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "free_sent_reliable %u %lX\n", mid, bitfield);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " rel %p, head %p\n", rel, rel->head_sent);
- for (i = 0, r = 0, copy = rel->head_sent;
- i < 64 && NULL != copy && 0 != bitfield;
- i++)
+ switch (ch->state)
{
- 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 && GC_is_pid_bigger (target, copy->mid))
- copy = copy->next;
-
- /* Did we run out of copies? (previously freed, it's ok) */
- if (NULL == copy)
+ case CADET_CHANNEL_NEW:
+ /* this should be impossible */
+ GNUNET_break (0);
+ break;
+ case CADET_CHANNEL_LOOSE:
+ /* This makes no sense. */
+ GNUNET_break_op (0);
+ break;
+ case CADET_CHANNEL_OPEN_SENT:
+ if (NULL == ch->owner)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "run out of copies...\n");
- return r;
+ /* We're not the owner, wrong direction! */
+ GNUNET_break_op (0);
+ return;
}
-
- /* Did we overshoot the target? (previously freed, it's ok) */
- if (GC_is_pid_bigger (copy->mid, target))
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received CHANNEL_OPEN_ACK for waiting %s, entering READY state\n",
+ GCCH_2s (ch));
+ if (NULL != ch->retry_control_task) /* can be NULL if ch->is_loopback */
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " next copy %u\n", copy->mid);
- i += copy->mid - target - 1; /* MID: 90, t = 85, i += 4 (i++ later) */
- mask = (0x1LL << (i + 1)) - 1; /* Mask = i-th bit and all before */
- bitfield &= ~mask; /* Clear all bits up to MID - 1 */
- continue;
+ GNUNET_SCHEDULER_cancel (ch->retry_control_task);
+ ch->retry_control_task = NULL;
}
-
- /* Now copy->mid == target, free it */
- next = copy->next;
- GNUNET_break (GNUNET_YES != rel_message_free (copy, GNUNET_YES));
- r++;
- copy = next;
+ ch->state = CADET_CHANNEL_READY;
+ /* On first connect, send client as many ACKs as we allow messages
+ to be buffered! */
+ for (unsigned int i=0;i<ch->max_pending_messages;i++)
+ send_ack_to_client (ch,
+ GNUNET_YES);
+ break;
+ case CADET_CHANNEL_READY:
+ /* duplicate ACK, maybe we retried the CREATE. Ignore. */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received duplicate channel OPEN_ACK for %s\n",
+ GCCH_2s (ch));
+ GNUNET_STATISTICS_update (stats,
+ "# duplicate CREATE_ACKs",
+ 1,
+ GNUNET_NO);
+ break;
}
- LOG (GNUNET_ERROR_TYPE_DEBUG, "free_sent_reliable END\n");
- return r;
}
/**
- * 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.
+ * Test if element @a e1 comes before element @a e2.
*
- * @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.
+ * @param cls closure, to a flag where we indicate duplicate packets
+ * @param m1 a message of to sort
+ * @param m2 another message to sort
+ * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
*/
static int
-rel_message_free (struct CadetReliableMessage *copy, int update_time)
+is_before (void *cls,
+ struct CadetOutOfOrderMessage *m1,
+ struct CadetOutOfOrderMessage *m2)
{
- struct CadetChannelReliability *rel;
- struct GNUNET_TIME_Relative time;
+ int *duplicate = cls;
+ uint32_t v1 = ntohl (m1->mid.mid);
+ uint32_t v2 = ntohl (m2->mid.mid);
+ uint32_t delta;
- rel = copy->rel;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Freeing %u\n", copy->mid);
- if (GNUNET_YES == update_time)
+ delta = v2 - v1;
+ if (0 == delta)
+ *duplicate = GNUNET_YES;
+ if (delta > (uint32_t) INT_MAX)
{
- 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_DEBUG, " message time %12s\n",
- GNUNET_STRINGS_relative_time_to_string (time, GNUNET_NO));
- LOG (GNUNET_ERROR_TYPE_DEBUG, " new delay %12s\n",
- GNUNET_STRINGS_relative_time_to_string (rel->expected_delay,
- GNUNET_NO));
- rel->retry_timer = rel->expected_delay;
+ /* in overflow range, we can safely assume we wrapped around */
+ return GNUNET_NO;
}
else
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "batch free, ignoring timing\n");
- }
- rel->ch->pending_messages--;
- if (NULL != copy->chq)
- {
- GCT_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, " free send copy MID %u at %p\n",
- copy->mid, copy);
- GNUNET_free (copy);
-
- if (GNUNET_NO != rel->ch->destroy && 0 == rel->ch->pending_messages)
- {
- GCCH_destroy (rel->ch);
+ /* result is small, thus v2 > v1, thus m1 < m2 */
return GNUNET_YES;
}
- return GNUNET_NO;
}
/**
- * Channel was ACK'd by remote peer, mark as ready and cancel retransmission.
+ * We got payload data for a channel. Pass it on to the client
+ * and send an ACK to the other end (once flow control allows it!)
*
- * @param ch Channel to mark as ready.
- * @param fwd Was the ACK message a FWD ACK? (dest->root, SYNACK)
+ * @param ch channel that got data
+ * @param cti identifier of the connection that delivered the message
+ * @param msg message that was received
*/
-static void
-channel_confirm (struct CadetChannel *ch, int fwd)
+void
+GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+ const struct GNUNET_CADET_ChannelAppDataMessage *msg)
{
- struct CadetChannelReliability *rel;
- enum CadetChannelState oldstate;
-
- rel = fwd ? ch->root_rel : ch->dest_rel;
- if (NULL == rel)
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_CADET_LocalData *ld;
+ struct CadetChannelClient *ccc;
+ size_t payload_size;
+ struct CadetOutOfOrderMessage *com;
+ int duplicate;
+ uint32_t mid_min;
+ uint32_t mid_max;
+ uint32_t mid_msg;
+ uint32_t delta;
+
+ GNUNET_assert (GNUNET_NO == ch->is_loopback);
+ if ( (GNUNET_YES == ch->destroy) &&
+ (NULL == ch->owner) &&
+ (NULL == ch->dest) )
+ {
+ /* This client is gone, but we still have messages to send to
+ the other end (which is why @a ch is not yet dead). However,
+ we cannot pass messages to our client anymore. */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Dropping incoming payload on %s as this end is already closed\n",
+ GCCH_2s (ch));
+ /* send back DESTROY notification to stop further retransmissions! */
+ GCT_send_channel_destroy (ch->t,
+ ch->ctn);
+ return;
+ }
+ payload_size = ntohs (msg->header.size) - sizeof (*msg);
+ env = GNUNET_MQ_msg_extra (ld,
+ payload_size,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
+ ld->ccn = (NULL == ch->dest) ? ch->owner->ccn : ch->dest->ccn;
+ GNUNET_memcpy (&ld[1],
+ &msg[1],
+ payload_size);
+ ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
+ if ( (GNUNET_YES == ccc->client_ready) &&
+ ( (GNUNET_YES == ch->out_of_order) ||
+ (msg->mid.mid == ch->mid_recv.mid) ) )
{
- GNUNET_break (GNUNET_NO != ch->destroy);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Giving %u bytes of payload with MID %u from %s to client %s\n",
+ (unsigned int) payload_size,
+ ntohl (msg->mid.mid),
+ GCCH_2s (ch),
+ GSC_2s (ccc->c));
+ ccc->client_ready = GNUNET_NO;
+ GSC_send_to_client (ccc->c,
+ env);
+ ch->mid_recv.mid = htonl (1 + ntohl (ch->mid_recv.mid));
+ ch->mid_futures >>= 1;
+ send_channel_data_ack (ch);
return;
}
- LOG (GNUNET_ERROR_TYPE_DEBUG, " channel confirm %s %s\n",
- GC_f2s (fwd), GCCH_2s (ch));
- oldstate = ch->state;
- ch->state = CADET_CHANNEL_READY;
- if (CADET_CHANNEL_READY != oldstate || GNUNET_YES == is_loopback (ch))
+ if (GNUNET_YES == ch->reliable)
{
- rel->client_ready = GNUNET_YES;
- rel->expected_delay = rel->retry_timer;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " confirm retry timer %s\n",
- GNUNET_STRINGS_relative_time_to_string (rel->retry_timer, GNUNET_NO));
- if (GCT_get_connections_buffer (ch->t) > 0 || GCT_is_loopback (ch->t))
- send_client_ack (ch, fwd);
-
- if (NULL != rel->retry_task)
+ /* check if message ought to be dropped because it is ancient/too distant/duplicate */
+ mid_min = ntohl (ch->mid_recv.mid);
+ mid_max = mid_min + ch->max_pending_messages;
+ mid_msg = ntohl (msg->mid.mid);
+ if ( ( (uint32_t) (mid_msg - mid_min) > ch->max_pending_messages) ||
+ ( (uint32_t) (mid_max - mid_msg) > ch->max_pending_messages) )
{
- GNUNET_SCHEDULER_cancel (rel->retry_task);
- rel->retry_task = NULL;
- }
- else if (NULL != rel->uniq)
- {
- GCT_cancel (rel->uniq->tq);
- /* ch_message_sent will free and NULL uniq */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "%s at %u drops ancient or far-future message %u\n",
+ GCCH_2s (ch),
+ (unsigned int) mid_min,
+ ntohl (msg->mid.mid));
+
+ GNUNET_STATISTICS_update (stats,
+ "# duplicate DATA (ancient or future)",
+ 1,
+ GNUNET_NO);
+ GNUNET_MQ_discard (env);
+ send_channel_data_ack (ch);
+ return;
}
- else if (GNUNET_NO == is_loopback (ch))
+ /* mark bit for future ACKs */
+ delta = mid_msg - mid_min - 1; /* overflow/underflow are OK here */
+ if (delta < 64)
{
- /* We SHOULD have been trying to retransmit this! */
- GNUNET_break (0);
+ if (0 != (ch->mid_futures & (1LLU << delta)))
+ {
+ /* Duplicate within the queue, drop also */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
+ (unsigned int) payload_size,
+ GCCH_2s (ch),
+ ntohl (msg->mid.mid));
+ GNUNET_STATISTICS_update (stats,
+ "# duplicate DATA",
+ 1,
+ GNUNET_NO);
+ GNUNET_MQ_discard (env);
+ send_channel_data_ack (ch);
+ return;
+ }
+ ch->mid_futures |= (1LLU << delta);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Marked bit %llX for mid %u (base: %u); now: %llX\n",
+ (1LLU << delta),
+ mid_msg,
+ mid_min,
+ ch->mid_futures);
}
}
-
- /* In case of a FWD ACK (SYNACK) send a BCK ACK (ACK). */
- if (GNUNET_YES == fwd)
- send_ack (ch, 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 MID %u %s\n", mid, GC_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;
- GNUNET_memcpy (&copy[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 CadetTunnel *t,
- struct CadetClient *owner,
- struct GNUNET_CADET_ClientChannelNumber 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 = GCT_get_next_ctn (t);
- GML_channel_add (owner, lid_root, ch);
- }
- GCT_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",
- GC_f2s (fwd), GC_m2s (type));
-
- switch (type)
+ else /* ! ch->reliable */
{
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_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_ChannelAppDataMessage *) msgh)->mid), ntohs (msgh->size));
- GCCH_handle_data (ch, (struct GNUNET_CADET_ChannelAppDataMessage *) msgh, fwd);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK:
- GCCH_handle_data_ack (ch,
- (const struct GNUNET_CADET_ChannelDataAckMessage *) msgh, fwd);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN:
- GCCH_handle_create (ch->t,
- (const struct GNUNET_CADET_ChannelOpenMessage *) msgh);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK:
- GCCH_handle_ack (ch,
- (const struct GNUNET_CADET_ChannelManageMessage *) msgh,
- fwd);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED:
- GCCH_handle_nack (ch);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
- GCCH_handle_destroy (ch,
- (const struct GNUNET_CADET_ChannelManageMessage *) msgh,
- fwd);
- break;
+ /* Channel is unreliable, so we do not ACK. But we also cannot
+ allow buffering everything, so check if we have space... */
+ if (ccc->num_recv >= ch->max_pending_messages)
+ {
+ struct CadetOutOfOrderMessage *drop;
- default:
- GNUNET_break_op (0);
+ /* Yep, need to drop. Drop the oldest message in
+ the buffer. */
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "end-to-end message not known (%u)\n",
- ntohs (msgh->type));
+ "Queue full due slow client on %s, dropping oldest message\n",
+ GCCH_2s (ch));
+ GNUNET_STATISTICS_update (stats,
+ "# messages dropped due to slow client",
+ 1,
+ GNUNET_NO);
+ drop = ccc->head_recv;
+ GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
+ ccc->tail_recv,
+ drop);
+ ccc->num_recv--;
+ GNUNET_MQ_discard (drop->env);
+ GNUNET_free (drop);
+ }
}
-}
-
-
-
-/******************************************************************************/
-/******************************** API ***********************************/
-/******************************************************************************/
-
-/**
- * Destroy a channel and free all resources.
- *
- * @param ch Channel to destroy.
- */
-void
-GCCH_destroy (struct CadetChannel *ch)
-{
- struct CadetClient *c;
- struct CadetTunnel *t;
- if (NULL == ch)
+ /* Insert message into sorted out-of-order queue */
+ com = GNUNET_new (struct CadetOutOfOrderMessage);
+ com->mid = msg->mid;
+ com->env = env;
+ duplicate = GNUNET_NO;
+ GNUNET_CONTAINER_DLL_insert_sorted (struct CadetOutOfOrderMessage,
+ is_before,
+ &duplicate,
+ ccc->head_recv,
+ ccc->tail_recv,
+ com);
+ ccc->num_recv++;
+ if (GNUNET_YES == duplicate)
+ {
+ /* Duplicate within the queue, drop also (this is not covered by
+ the case above if "delta" >= 64, which could be the case if
+ max_pending_messages is also >= 64 or if our client is unready
+ and we are seeing retransmissions of the message our client is
+ blocked on. */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
+ (unsigned int) payload_size,
+ GCCH_2s (ch),
+ ntohl (msg->mid.mid));
+ GNUNET_STATISTICS_update (stats,
+ "# duplicate DATA",
+ 1,
+ GNUNET_NO);
+ GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
+ ccc->tail_recv,
+ com);
+ ccc->num_recv--;
+ GNUNET_MQ_discard (com->env);
+ GNUNET_free (com);
+ send_channel_data_ack (ch);
return;
- if (2 == ch->destroy)
- return; /* recursive call */
- ch->destroy = 2;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying channel %s:%u\n",
- GCT_2s (ch->t), ch->gid);
- GCCH_debug (ch, GNUNET_ERROR_TYPE_DEBUG);
-
- 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;
- GCT_remove_channel (t, ch);
- GNUNET_STATISTICS_update (stats, "# channels", -1, GNUNET_NO);
-
- GNUNET_free (ch);
- GCT_destroy_if_empty (t);
-}
-
-
-/**
- * Get the channel's public ID.
- *
- * @param ch Channel.
- *
- * @return ID used to identify the channel with the remote peer.
- */
-struct GNUNET_CADET_ChannelTunnelNumber
-GCCH_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 CadetTunnel *
-GCCH_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
-GCCH_get_buffer (struct CadetChannel *ch, int fwd)
-{
- struct CadetChannelReliability *rel;
-
- rel = fwd ? ch->dest_rel : ch->root_rel;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " get buffer, channel %s\n", GCCH_2s (ch));
- GCCH_debug (ch, GNUNET_ERROR_TYPE_DEBUG);
- /* 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)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " rel is NULL: max\n");
- return 64;
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " n_recv %d\n", rel->n_recv);
- 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
-GCCH_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;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Queued %s payload of %u bytes on %s-%X(%p) (mid %u, need %u first)\n",
+ (GNUNET_YES == ccc->client_ready)
+ ? "out-of-order"
+ : "client-not-ready",
+ (unsigned int) payload_size,
+ GCCH_2s (ch),
+ ntohl (ccc->ccn.channel_of_client),
+ ccc,
+ ntohl (msg->mid.mid),
+ ntohl (ch->mid_recv.mid));
+ /* NOTE: this ACK we _could_ skip, as the packet is out-of-order and
+ the sender may already be transmitting the previous one. Needs
+ experimental evaluation to see if/when this ACK helps or
+ hurts. (We might even want another option.) */
+ send_channel_data_ack (ch);
}
/**
- * 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.
+ * Function called once the tunnel has sent one of our messages.
+ * If the message is unreliable, simply frees the `crm`. If the
+ * message was reliable, calculate retransmission time and
+ * wait for ACK (or retransmit).
+ *
+ * @param cls the `struct CadetReliableMessage` that was sent
+ * @param cid identifier of the connection within the tunnel, NULL
+ * if transmission failed
*/
-int
-GCCH_is_origin (struct CadetChannel *ch, int fwd)
-{
- struct CadetClient *c;
-
- c = fwd ? ch->root : ch->dest;
- return NULL != c;
-}
+static void
+data_sent_cb (void *cls,
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
/**
- * Is the destination client for this channel on this peer?
- *
- * @param ch Channel.
- * @param fwd Is this for fwd traffic?
+ * We need to retry a transmission, the last one took too long to
+ * be acknowledged.
*
- * @return #GNUNET_YES in case it is.
+ * @param cls the `struct CadetChannel` where we need to retransmit
*/
-int
-GCCH_is_terminal (struct CadetChannel *ch, int fwd)
+static void
+retry_transmission (void *cls)
{
- struct CadetClient *c;
+ struct CadetChannel *ch = cls;
+ struct CadetReliableMessage *crm = ch->head_sent;
- c = fwd ? ch->dest : ch->root;
- return NULL != c;
+ ch->retry_data_task = NULL;
+ GNUNET_assert (NULL == crm->qe);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Retrying transmission on %s of message %u\n",
+ GCCH_2s (ch),
+ (unsigned int) ntohl (crm->data_message->mid.mid));
+ crm->qe = GCT_send (ch->t,
+ &crm->data_message->header,
+ &data_sent_cb,
+ crm);
+ GNUNET_assert (NULL == ch->retry_data_task);
}
/**
- * Send an end-to-end ACK message for the most recent in-sequence payload.
+ * We got an PLAINTEXT_DATA_ACK for a message in our queue, remove it from
+ * the queue and tell our client that it can send more.
*
- * If channel is not reliable, do nothing.
- *
- * @param ch Channel this is about.
- * @param fwd Is for FWD traffic? (ACK dest->owner)
+ * @param ch the channel that got the PLAINTEXT_DATA_ACK
+ * @param cti identifier of the connection that delivered the message
+ * @param crm the message that got acknowledged
*/
-void
-GCCH_send_data_ack (struct CadetChannel *ch, int fwd)
+static void
+handle_matching_ack (struct CadetChannel *ch,
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+ struct CadetReliableMessage *crm)
{
- struct GNUNET_CADET_ChannelDataAckMessage 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;
-
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK);
- msg.header.size = htons (sizeof (msg));
- msg.ctn = ch->gid;
- msg.mid = htonl (ack);
-
- msg.futures = 0LL;
- for (copy = rel->head_recv; NULL != copy; copy = copy->next)
- {
- if (copy->type != GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA)
+ GNUNET_CONTAINER_DLL_remove (ch->head_sent,
+ ch->tail_sent,
+ crm);
+ ch->pending_messages--;
+ GNUNET_assert (ch->pending_messages < ch->max_pending_messages);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received DATA_ACK on %s for message %u (%u ACKs pending)\n",
+ GCCH_2s (ch),
+ (unsigned int) ntohl (crm->data_message->mid.mid),
+ ch->pending_messages);
+ if (NULL != crm->qe)
+ {
+ GCT_send_cancel (crm->qe);
+ crm->qe = NULL;
+ }
+ if ( (1 == crm->num_transmissions) &&
+ (NULL != cti) )
+ {
+ GCC_ack_observed (cti);
+ if (0 == memcmp (cti,
+ &crm->connection_taken,
+ sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier)))
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Type %s, expected DATA\n",
- GC_m2s (copy->type));
- continue;
+ GCC_latency_observed (cti,
+ GNUNET_TIME_absolute_get_duration (crm->first_transmission_time));
}
- GNUNET_assert (GC_is_pid_bigger(copy->mid, ack));
- 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) (%lX) -> %lX\n",
- copy->mid, delta, mask, msg.futures);
}
-
- GCCH_send_prebuilt_message (&msg.header, ch, !fwd, NULL);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "send_data_ack END\n");
+ GNUNET_free (crm->data_message);
+ GNUNET_free (crm);
+ send_ack_to_client (ch,
+ (NULL == ch->owner)
+ ? GNUNET_NO
+ : GNUNET_YES);
}
/**
- * Allow a client to send us more data, in case it was choked.
+ * We got an acknowledgement for payload data for a channel.
+ * Possibly resume transmissions.
*
- * @param ch Channel.
- * @param fwd Is this about FWD traffic? (Root client).
+ * @param ch channel that got the ack
+ * @param cti identifier of the connection that delivered the message
+ * @param ack details about what was received
*/
void
-GCCH_allow_client (struct CadetChannel *ch, int fwd)
+GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+ const struct GNUNET_CADET_ChannelDataAckMessage *ack)
{
- struct CadetChannelReliability *rel;
- unsigned int buffer;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GMCH allow\n");
+ struct CadetReliableMessage *crm;
+ struct CadetReliableMessage *crmn;
+ int found;
+ uint32_t mid_base;
+ uint64_t mid_mask;
+ unsigned int delta;
- if (CADET_CHANNEL_READY != ch->state)
+ GNUNET_break (GNUNET_NO == ch->is_loopback);
+ if (GNUNET_NO == ch->reliable)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " channel not ready yet!\n");
+ /* not expecting ACKs on unreliable channel, odd */
+ GNUNET_break_op (0);
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)
+ /* mid_base is the MID of the next message that the
+ other peer expects (i.e. that is missing!), everything
+ LOWER (but excluding mid_base itself) was received. */
+ mid_base = ntohl (ack->mid.mid);
+ mid_mask = GNUNET_htonll (ack->futures);
+ found = GNUNET_NO;
+ for (crm = ch->head_sent;
+ NULL != crm;
+ crm = crmn)
+ {
+ crmn = crm->next;
+ delta = (unsigned int) (ntohl (crm->data_message->mid.mid) - mid_base);
+ if (delta >= UINT_MAX - ch->max_pending_messages)
{
- 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);
- struct CadetReliableMessage *aux;
- for (aux = rel->head_sent; NULL != aux; aux = aux->next)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " - sent mid %u\n", aux->mid);
- }
- }
+ /* overflow, means crm was a bit in the past, so this ACK counts for it. */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Got DATA_ACK with base %u satisfying past message %u on %s\n",
+ (unsigned int) mid_base,
+ ntohl (crm->data_message->mid.mid),
+ GCCH_2s (ch));
+ handle_matching_ack (ch,
+ cti,
+ crm);
+ found = GNUNET_YES;
+ continue;
}
- else
+ delta--;
+ if (delta >= 64)
+ continue;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Testing bit %llX for mid %u (base: %u)\n",
+ (1LLU << delta),
+ ntohl (crm->data_message->mid.mid),
+ mid_base);
+ if (0 != (mid_mask & (1LLU << delta)))
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " head sent is NULL\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Got DATA_ACK with mask for %u on %s\n",
+ ntohl (crm->data_message->mid.mid),
+ GCCH_2s (ch));
+ handle_matching_ack (ch,
+ cti,
+ crm);
+ found = GNUNET_YES;
}
}
-
- if (is_loopback (ch))
- buffer = GCCH_get_buffer (ch, fwd);
- else
- buffer = GCT_get_connections_buffer (ch->t);
-
- if (0 == buffer)
+ if (GNUNET_NO == found)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " no buffer space.\n");
+ /* ACK for message we already dropped, might have been a
+ duplicate ACK? Ignore. */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Duplicate DATA_ACK on %s, ignoring\n",
+ GCCH_2s (ch));
+ GNUNET_STATISTICS_update (stats,
+ "# duplicate DATA_ACKs",
+ 1,
+ GNUNET_NO);
return;
}
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space %u, allowing\n", buffer);
- send_client_ack (ch, fwd);
+ if (NULL != ch->retry_data_task)
+ {
+ GNUNET_SCHEDULER_cancel (ch->retry_data_task);
+ ch->retry_data_task = NULL;
+ }
+ if ( (NULL != ch->head_sent) &&
+ (NULL == ch->head_sent->qe) )
+ ch->retry_data_task
+ = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
+ &retry_transmission,
+ ch);
}
/**
- * Log channel info.
+ * Destroy channel, based on the other peer closing the
+ * connection. Also needs to remove this channel from
+ * the tunnel.
*
- * @param ch Channel.
- * @param level Debug level to use.
+ * @param ch channel to destroy
+ * @param cti identifier of the connection that delivered the message,
+ * NULL if we are simulating receiving a destroy due to shutdown
*/
void
-GCCH_debug (struct CadetChannel *ch, enum GNUNET_ErrorType level)
+GCCH_handle_remote_destroy (struct CadetChannel *ch,
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
{
- int do_log;
+ struct CadetChannelClient *ccc;
- do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
- "cadet-chn",
- __FILE__, __FUNCTION__, __LINE__);
- if (0 == do_log)
- return;
-
- if (NULL == ch)
+ GNUNET_assert (GNUNET_NO == ch->is_loopback);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received remote channel DESTROY for %s\n",
+ GCCH_2s (ch));
+ if (GNUNET_YES == ch->destroy)
{
- LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n");
+ /* Local client already gone, this is instant-death. */
+ channel_destroy (ch);
return;
}
- LOG2 (level, "CHN Channel %s:%X (%p)\n", GCT_2s (ch->t), ch->gid, ch);
- LOG2 (level, "CHN root %p/%p\n", ch->root, ch->root_rel);
- if (NULL != ch->root)
- {
- LOG2 (level, "CHN cli %s\n", GML_2s (ch->root));
- LOG2 (level, "CHN ready %s\n", ch->root_rel->client_ready ? "YES" : "NO");
- LOG2 (level, "CHN id %X\n", ch->lid_root.channel_of_client);
- LOG2 (level, "CHN recv %d\n", ch->root_rel->n_recv);
- LOG2 (level, "CHN MID r: %d, s: %d\n",
- ch->root_rel->mid_recv, ch->root_rel->mid_send);
- }
- LOG2 (level, "CHN dest %p/%p\n",
- ch->dest, ch->dest_rel);
- if (NULL != ch->dest)
+ ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
+ if ( (NULL != ccc) &&
+ (NULL != ccc->head_recv) )
{
- LOG2 (level, "CHN cli %s\n", GML_2s (ch->dest));
- LOG2 (level, "CHN ready %s\n", ch->dest_rel->client_ready ? "YES" : "NO");
- LOG2 (level, "CHN id %X\n", ch->lid_dest);
- LOG2 (level, "CHN recv %d\n", ch->dest_rel->n_recv);
- LOG2 (level, "CHN MID r: %d, s: %d\n",
- ch->dest_rel->mid_recv, ch->dest_rel->mid_send);
-
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Lost end of transmission due to remote shutdown on %s\n",
+ GCCH_2s (ch));
+ /* FIXME: change API to notify client about truncated transmission! */
}
+ ch->destroy = GNUNET_YES;
+ if (NULL != ccc)
+ GSC_handle_remote_channel_destroy (ccc->c,
+ ccc->ccn,
+ ch);
+ channel_destroy (ch);
}
/**
- * Handle an ACK given by a client.
- *
- * Mark client as ready and send him any buffered data we could have for him.
+ * Test if element @a e1 comes before element @a e2.
*
- * @param ch Channel.
- * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by dest and go BCK)
+ * @param cls closure, to a flag where we indicate duplicate packets
+ * @param crm1 an element of to sort
+ * @param crm2 another element to sort
+ * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
*/
-void
-GCCH_handle_local_ack (struct CadetChannel *ch, int fwd)
+static int
+cmp_crm_by_next_retry (void *cls,
+ struct CadetReliableMessage *crm1,
+ struct CadetReliableMessage *crm2)
{
- 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);
- GCCH_destroy (ch);
- return;
- }
- /* 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 = GCCH_get_buffer (ch, fwd);
- if (0 < buffer)
- GCCH_allow_client (ch, fwd);
-
- return;
- }
- GCT_send_connection_acks (ch->t);
+ if (crm1->next_retry.abs_value_us <
+ crm2->next_retry.abs_value_us)
+ return GNUNET_YES;
+ return GNUNET_NO;
}
/**
- * 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 fwd Is this a FWD data?
- * @param message Data message.
- * @param size Size of data.
- *
- * @return #GNUNET_OK if everything goes well, #GNUNET_SYSERR in case of en error.
+ * Function called once the tunnel has sent one of our messages.
+ * If the message is unreliable, simply frees the `crm`. If the
+ * message was reliable, calculate retransmission time and
+ * wait for ACK (or retransmit).
+ *
+ * @param cls the `struct CadetReliableMessage` that was sent
+ * @param cid identifier of the connection within the tunnel, NULL
+ * if transmission failed
*/
-int
-GCCH_handle_local_data (struct CadetChannel *ch,
- struct CadetClient *c,
- int fwd,
- const struct GNUNET_MessageHeader *message,
- size_t size)
+static void
+data_sent_cb (void *cls,
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
{
- struct CadetChannelReliability *rel;
- struct GNUNET_CADET_ChannelAppDataMessage *payload;
- uint16_t p2p_size = sizeof(struct GNUNET_CADET_ChannelAppDataMessage) + size;
- unsigned char cbuf[p2p_size];
- unsigned char buffer;
-
- /* Is the client in the channel? */
- if ( !( (fwd &&
- ch->root == c)
- ||
- (!fwd &&
- ch->dest == c) ) )
+ struct CadetReliableMessage *crm = cls;
+ struct CadetChannel *ch = crm->ch;
+
+ GNUNET_assert (GNUNET_NO == ch->is_loopback);
+ GNUNET_assert (NULL != crm->qe);
+ crm->qe = NULL;
+ GNUNET_CONTAINER_DLL_remove (ch->head_sent,
+ ch->tail_sent,
+ crm);
+ if (GNUNET_NO == ch->reliable)
{
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
+ GNUNET_free (crm->data_message);
+ GNUNET_free (crm);
+ ch->pending_messages--;
+ send_ack_to_client (ch,
+ (NULL == ch->owner)
+ ? GNUNET_NO
+ : GNUNET_YES);
+ return;
}
-
- rel = fwd ? ch->root_rel : ch->dest_rel;
-
- if (GNUNET_NO == rel->client_allowed)
+ if (NULL == cid)
{
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
+ /* There was an error sending. */
+ crm->num_transmissions = GNUNET_SYSERR;
}
-
- rel->client_allowed = GNUNET_NO;
-
- /* Ok, everything is correct, send the message. */
- payload = (struct GNUNET_CADET_ChannelAppDataMessage *) cbuf;
- payload->mid = htonl (rel->mid_send);
- rel->mid_send++;
- GNUNET_memcpy (&payload[1], message, size);
- payload->header.size = htons (p2p_size);
- payload->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA);
- payload->ctn = ch->gid;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channel...\n");
- GCCH_send_prebuilt_message (&payload->header, ch, fwd, NULL);
-
- if (is_loopback (ch))
- buffer = GCCH_get_buffer (ch, fwd);
- else
- buffer = GCT_get_connections_buffer (ch->t);
-
- if (0 < buffer)
- GCCH_allow_client (ch, fwd);
-
- return GNUNET_OK;
-}
-
-
-/**
- * Handle a channel destroy requested by a client.
- *
- * TODO: add "reason" field
- *
- * 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
-GCCH_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)
+ else if (GNUNET_SYSERR != crm->num_transmissions)
{
- 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;
+ /* Increment transmission counter, and possibly store @a cid
+ if this was the first transmission. */
+ crm->num_transmissions++;
+ if (1 == crm->num_transmissions)
+ {
+ crm->first_transmission_time = GNUNET_TIME_absolute_get ();
+ crm->connection_taken = *cid;
+ GCC_ack_expected (cid);
+ }
}
- if (GNUNET_YES == is_root && c == ch->root)
+ if ( (0 == crm->retry_delay.rel_value_us) &&
+ (NULL != cid) )
{
- 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;
- }
+ struct CadetConnection *cc = GCC_lookup (cid);
- send_destroy (ch, GNUNET_NO);
- if (0 == ch->pending_messages)
- GCCH_destroy (ch);
+ if (NULL != cc)
+ crm->retry_delay = GCC_get_metrics (cc)->aged_latency;
+ else
+ crm->retry_delay = ch->retry_time;
+ }
+ crm->retry_delay = GNUNET_TIME_STD_BACKOFF (crm->retry_delay);
+ crm->retry_delay = GNUNET_TIME_relative_max (crm->retry_delay,
+ MIN_RTT_DELAY);
+ crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay);
+
+ GNUNET_CONTAINER_DLL_insert_sorted (struct CadetReliableMessage,
+ cmp_crm_by_next_retry,
+ NULL,
+ ch->head_sent,
+ ch->tail_sent,
+ crm);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Message %u sent, next transmission on %s in %s\n",
+ (unsigned int) ntohl (crm->data_message->mid.mid),
+ GCCH_2s (ch),
+ GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (ch->head_sent->next_retry),
+ GNUNET_YES));
+ if (NULL == ch->head_sent->qe)
+ {
+ if (NULL != ch->retry_data_task)
+ GNUNET_SCHEDULER_cancel (ch->retry_data_task);
+ ch->retry_data_task
+ = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
+ &retry_transmission,
+ ch);
+ }
}
/**
- * Handle a channel create requested by a client.
- *
- * Create the channel and the tunnel in case this was the first0 channel.
+ * Handle data given by a client.
*
- * @param c Client that requested the creation (will be the root).
- * @param msg Create Channel message.
+ * 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.
*
- * @return #GNUNET_OK if everything went fine, #GNUNET_SYSERR otherwise.
+ * @param ch Channel.
+ * @param sender_ccn ccn of the sender
+ * @param buf payload to transmit.
+ * @param buf_len number of bytes in @a buf
+ * @return #GNUNET_OK if everything goes well,
+ * #GNUNET_SYSERR in case of an error.
*/
int
-GCCH_handle_local_create (struct CadetClient *c,
- struct GNUNET_CADET_LocalChannelCreateMessage *msg)
+GCCH_handle_local_data (struct CadetChannel *ch,
+ struct GNUNET_CADET_ClientChannelNumber sender_ccn,
+ const char *buf,
+ size_t buf_len)
{
- struct CadetChannel *ch;
- struct CadetTunnel *t;
- struct CadetPeer *peer;
- struct GNUNET_CADET_ClientChannelNumber ccn;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " towards %s:%u\n",
- GNUNET_i2s (&msg->peer), GNUNET_h2s (&msg->port));
- ccn = msg->ccn;
-
- /* Sanity check for duplicate channel IDs */
- if (NULL != GML_channel_get (c, ccn))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
+ struct CadetReliableMessage *crm;
- peer = GCP_get (&msg->peer, GNUNET_YES);
- GCP_add_tunnel (peer);
- t = GCP_get_tunnel (peer);
-
- if (GCP_get_short_id (peer) == myid)
- {
- GCT_change_cstate (t, CADET_TUNNEL_READY);
- }
- else
- {
- /* FIXME change to a tunnel API, eliminate ch <-> peer connection */
- GCP_connect (peer);
- }
-
- /* Create channel */
- ch = channel_new (t, c, ccn);
- if (NULL == ch)
+ if (ch->pending_messages > ch->max_pending_messages)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
- ch->port = 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", GCCH_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
-GCCH_handle_data (struct CadetChannel *ch,
- const struct GNUNET_CADET_ChannelAppDataMessage *msg,
- int fwd)
-{
- struct CadetChannelReliability *rel;
- struct CadetClient *c;
- struct GNUNET_MessageHeader *payload_msg;
- uint32_t mid;
- uint16_t payload_type;
- uint16_t payload_size;
-
- /* If this is a remote (non-loopback) channel, find 'fwd'. */
- if (GNUNET_SYSERR == fwd)
+ if (GNUNET_YES == ch->destroy)
{
- if (is_loopback (ch))
- {
- /* It is a loopback channel after all... */
- GNUNET_break (0);
- return;
- }
- fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO;
+ /* we are going down, drop messages */
+ return GNUNET_OK;
}
+ ch->pending_messages++;
- /* Initialize FWD/BCK data */
- c = fwd ? ch->dest : ch->root;
- rel = fwd ? ch->dest_rel : ch->root_rel;
-
- if (NULL == c)
+ if (GNUNET_YES == ch->is_loopback)
{
- GNUNET_break (GNUNET_NO != ch->destroy);
- return;
- }
+ struct CadetChannelClient *receiver;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_CADET_LocalData *ld;
+ int ack_to_owner;
- if (CADET_CHANNEL_READY != ch->state)
- {
- if (GNUNET_NO == fwd)
+ env = GNUNET_MQ_msg_extra (ld,
+ buf_len,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
+ if ( (NULL != ch->owner) &&
+ (sender_ccn.channel_of_client ==
+ ch->owner->ccn.channel_of_client) )
{
- /* 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;
+ receiver = ch->dest;
+ ack_to_owner = GNUNET_YES;
}
- /* 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);
- }
-
- payload_msg = (struct GNUNET_MessageHeader *) &msg[1];
- payload_type = ntohs (payload_msg->type);
- payload_size = ntohs (payload_msg->size);
-
- GNUNET_STATISTICS_update (stats, "# messages received", 1, GNUNET_NO);
- GNUNET_STATISTICS_update (stats, "# bytes received", payload_size, GNUNET_NO);
-
- mid = ntohl (msg->mid);
- LOG (GNUNET_ERROR_TYPE_INFO, "<== %s (%s %4u) on chan %s (%p) %s [%5u]\n",
- GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA), GC_m2s (payload_type), mid,
- GCCH_2s (ch), ch, GC_f2s (fwd), ntohs (msg->header.size));
-
- if ( (GNUNET_NO == ch->reliable) ||
- ( (! GC_is_pid_bigger (rel->mid_recv, mid)) &&
- GC_is_pid_bigger (rel->mid_recv + 64, mid) ) )
- {
- if (GNUNET_YES == ch->reliable)
+ else if ( (NULL != ch->dest) &&
+ (sender_ccn.channel_of_client ==
+ ch->dest->ccn.channel_of_client) )
{
- /* Is this the exact next expected messasge? */
- if (mid == rel->mid_recv)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "as expected, sending to client\n");
- send_client_data (ch, msg, fwd);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "save for later\n");
- add_buffered_data (msg, rel);
- }
+ receiver = ch->owner;
+ ack_to_owner = GNUNET_NO;
}
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);
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
}
- }
- else
- {
- GNUNET_STATISTICS_update (stats, "# duplicate MID", 1, GNUNET_NO);
- if (GC_is_pid_bigger (rel->mid_recv, mid))
+ GNUNET_assert (NULL != receiver);
+ ld->ccn = receiver->ccn;
+ GNUNET_memcpy (&ld[1],
+ buf,
+ buf_len);
+ if (GNUNET_YES == receiver->client_ready)
{
- GNUNET_break_op (0);
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "MID %u on channel %s not expected (window: %u - %u). Dropping!\n",
- mid, GCCH_2s (ch), rel->mid_recv, rel->mid_recv + 63);
+ ch->pending_messages--;
+ GSC_send_to_client (receiver->c,
+ env);
+ send_ack_to_client (ch,
+ ack_to_owner);
}
else
{
- LOG (GNUNET_ERROR_TYPE_INFO,
- "Duplicate MID %u, channel %s (expecting MID %u). Re-sending ACK!\n",
- mid, GCCH_2s (ch), rel->mid_recv);
- if (NULL != rel->uniq)
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "We are trying to send an ACK, but don't seem have the "
- "bandwidth. Have you set enough [ats] QUOTA in your config?\n");
- }
-
+ struct CadetOutOfOrderMessage *oom;
+
+ oom = GNUNET_new (struct CadetOutOfOrderMessage);
+ oom->env = env;
+ GNUNET_CONTAINER_DLL_insert_tail (receiver->head_recv,
+ receiver->tail_recv,
+ oom);
+ receiver->num_recv++;
}
- }
-
- GCCH_send_data_ack (ch, fwd);
+ return GNUNET_OK;
+ }
+
+ /* Everything is correct, send the message. */
+ crm = GNUNET_malloc (sizeof (*crm));
+ crm->ch = ch;
+ crm->data_message = GNUNET_malloc (sizeof (struct GNUNET_CADET_ChannelAppDataMessage)
+ + buf_len);
+ crm->data_message->header.size = htons (sizeof (struct GNUNET_CADET_ChannelAppDataMessage) + buf_len);
+ crm->data_message->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA);
+ ch->mid_send.mid = htonl (ntohl (ch->mid_send.mid) + 1);
+ crm->data_message->mid = ch->mid_send;
+ crm->data_message->ctn = ch->ctn;
+ GNUNET_memcpy (&crm->data_message[1],
+ buf,
+ buf_len);
+ GNUNET_CONTAINER_DLL_insert_tail (ch->head_sent,
+ ch->tail_sent,
+ crm);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending message %u from local client to %s with %u bytes\n",
+ ntohl (crm->data_message->mid.mid),
+ GCCH_2s (ch),
+ buf_len);
+ if (NULL != ch->retry_data_task)
+ {
+ GNUNET_SCHEDULER_cancel (ch->retry_data_task);
+ ch->retry_data_task = NULL;
+ }
+ crm->qe = GCT_send (ch->t,
+ &crm->data_message->header,
+ &data_sent_cb,
+ crm);
+ GNUNET_assert (NULL == ch->retry_data_task);
+ return GNUNET_OK;
}
/**
- * Handler for cadet network traffic end-to-end ACKs.
+ * Handle ACK from client on local channel. Means the client is ready
+ * for more data, see if we have any for it.
*
- * @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)
+ * @param ch channel to destroy
+ * @param client_ccn ccn of the client sending the ack
*/
void
-GCCH_handle_data_ack (struct CadetChannel *ch,
- const struct GNUNET_CADET_ChannelDataAckMessage *msg,
- int fwd)
+GCCH_handle_local_ack (struct CadetChannel *ch,
+ struct GNUNET_CADET_ClientChannelNumber client_ccn)
{
- 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 (0x%010lX %4u) on chan %s (%p) %s [%5u]\n",
- GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK), msg->futures, ack,
- GCCH_2s (ch), ch, GC_f2s (fwd), ntohs (msg->header.size));
-
- if (GNUNET_YES == fwd)
- rel = ch->root_rel;
+ struct CadetChannelClient *ccc;
+ struct CadetOutOfOrderMessage *com;
+
+ if ( (NULL != ch->owner) &&
+ (ch->owner->ccn.channel_of_client == client_ccn.channel_of_client) )
+ ccc = ch->owner;
+ else if ( (NULL != ch->dest) &&
+ (ch->dest->ccn.channel_of_client == client_ccn.channel_of_client) )
+ ccc = ch->dest;
else
- rel = ch->dest_rel;
-
- if (NULL == rel)
+ GNUNET_assert (0);
+ ccc->client_ready = GNUNET_YES;
+ com = ccc->head_recv;
+ if (NULL == com)
{
- GNUNET_break (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 (GC_is_pid_bigger (copy->mid, ack))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " head %u, out!\n", copy->mid);
- if (0 < channel_rel_free_sent (rel, msg))
- work = GNUNET_YES;
- 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))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " channel destoyed\n");
- return;
- }
- }
-
- /* ACK client if needed and possible */
- GCCH_allow_client (ch, fwd);
-
- /* If some message was free'd, update the retransmission delay */
- if (GNUNET_YES == work)
- {
- if (NULL != rel->retry_task)
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Got LOCAL_ACK, %s-%X ready to receive more data, but none pending on %s-%X(%p)!\n",
+ GSC_2s (ccc->c),
+ ntohl (client_ccn.channel_of_client),
+ GCCH_2s (ch),
+ ntohl (ccc->ccn.channel_of_client),
+ ccc);
+ return; /* none pending */
+ }
+ if (GNUNET_YES == ch->is_loopback)
+ {
+ int to_owner;
+
+ /* Messages are always in-order, just send */
+ GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
+ ccc->tail_recv,
+ com);
+ ccc->num_recv--;
+ GSC_send_to_client (ccc->c,
+ com->env);
+ /* Notify sender that we can receive more */
+ if ( (NULL != ch->owner) &&
+ (ccc->ccn.channel_of_client ==
+ ch->owner->ccn.channel_of_client) )
{
- GNUNET_SCHEDULER_cancel (rel->retry_task);
- rel->retry_task = NULL;
- 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_saturating_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);
- }
+ to_owner = GNUNET_NO;
}
else
{
- /* Work was done but no task was pending.
- * Task was cancelled by a retransmission that is sitting in the queue.
- */
- // FIXME add test to make sure this is the case, probably add return
- // value to GCCH_send_prebuilt_message
+ GNUNET_assert ( (NULL != ch->dest) &&
+ (ccc->ccn.channel_of_client ==
+ ch->dest->ccn.channel_of_client) );
+ to_owner = GNUNET_YES;
}
+ send_ack_to_client (ch,
+ to_owner);
+ GNUNET_free (com);
+ return;
}
-}
-
-/**
- * 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 *
-GCCH_handle_create (struct CadetTunnel *t,
- const struct GNUNET_CADET_ChannelOpenMessage *msg)
-{
- struct GNUNET_CADET_ClientChannelNumber ccn;
- struct GNUNET_CADET_ChannelTunnelNumber gid;
- struct CadetChannel *ch;
- struct CadetClient *c;
- int new_channel;
- const struct GNUNET_HashCode *port;
-
- gid = msg->ctn;
- ch = GCT_get_channel (t, gid);
- if (NULL == ch)
- {
- /* Create channel */
- ccn.channel_of_client = htonl (0);
- ch = channel_new (t, NULL, ccn);
- ch->gid = gid;
- channel_set_options (ch, ntohl (msg->opt));
- new_channel = GNUNET_YES;
- }
- else
+ if ( (com->mid.mid != ch->mid_recv.mid) &&
+ (GNUNET_NO == ch->out_of_order) &&
+ (GNUNET_YES == ch->reliable) )
{
- new_channel = GNUNET_NO;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Got LOCAL_ACK, %s-%X ready to receive more data (but next one is out-of-order %u vs. %u)!\n",
+ GSC_2s (ccc->c),
+ ntohl (ccc->ccn.channel_of_client),
+ ntohl (com->mid.mid),
+ ntohl (ch->mid_recv.mid));
+ return; /* missing next one in-order */
}
- port = &msg->port;
-
- LOG (GNUNET_ERROR_TYPE_INFO,
- "<== %s ( 0x%08X %4u) on chan %s (%p) %s [%5u]\n",
- GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN), ccn, port,
- GCCH_2s (ch), ch, GC_f2s (GNUNET_YES), ntohs (msg->header.size));
-
- if (GNUNET_YES == new_channel || GCT_is_loopback (t))
- {
- /* Find a destination client */
- ch->port = *port;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " port %s\n", GNUNET_h2s (port));
- c = GML_client_get_by_port (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);
- GCCH_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");
- if (NULL != 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 = NULL;
- }
- else if (NULL != ch->dest_rel->uniq)
- {
- /* we are waiting to for our 'SYNACK' to leave the queue, all done! */
- return ch;
- }
- }
- send_ack (ch, GNUNET_YES);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Got LOCAL_ACK, giving payload message %u to %s-%X on %s\n",
+ ntohl (com->mid.mid),
+ GSC_2s (ccc->c),
+ ntohl (ccc->ccn.channel_of_client),
+ GCCH_2s (ch));
- return ch;
+ /* all good, pass next message to client */
+ GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
+ ccc->tail_recv,
+ com);
+ ccc->num_recv--;
+ /* FIXME: if unreliable, this is not aggressive
+ enough, as it would be OK to have lost some! */
+
+ ch->mid_recv.mid = htonl (1 + ntohl (com->mid.mid));
+ ch->mid_futures >>= 1; /* equivalent to division by 2 */
+ ccc->client_ready = GNUNET_NO;
+ GSC_send_to_client (ccc->c,
+ com->env);
+ GNUNET_free (com);
+ send_channel_data_ack (ch);
+ if (NULL != ccc->head_recv)
+ return;
+ if (GNUNET_NO == ch->destroy)
+ return;
+ GCT_send_channel_destroy (ch->t,
+ ch->ctn);
+ channel_destroy (ch);
}
-/**
- * Handler for channel NACK messages.
- *
- * NACK messages always go dest -> root, no need for 'fwd' or 'msg' parameter.
- *
- * @param ch Channel.
- */
-void
-GCCH_handle_nack (struct CadetChannel *ch)
-{
- LOG (GNUNET_ERROR_TYPE_INFO,
- "<== %s ( 0x%08X %4u) on chan %s (%p) %s [%5u]\n",
- GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED), ch->gid, 0,
- GCCH_2s (ch), ch, "---", 0);
-
- send_client_nack (ch);
- GCCH_destroy (ch);
-}
+#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-chn",__VA_ARGS__)
/**
- * Handler for channel ack messages.
+ * Log channel info.
*
* @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
-GCCH_handle_ack (struct CadetChannel *ch,
- const struct GNUNET_CADET_ChannelManageMessage *msg,
- int fwd)
-{
- LOG (GNUNET_ERROR_TYPE_INFO,
- "<== %s ( 0x%08X %4u) on chan %s (%p) %s [%5u]\n",
- GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK), ch->gid, 0,
- GCCH_2s (ch), ch, GC_f2s (fwd), ntohs (msg->header.size));
-
- /* 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)
+ * @param level Debug level to use.
*/
void
-GCCH_handle_destroy (struct CadetChannel *ch,
- const struct GNUNET_CADET_ChannelManageMessage *msg,
- int fwd)
+GCCH_debug (struct CadetChannel *ch,
+ enum GNUNET_ErrorType level)
{
- struct CadetChannelReliability *rel;
-
- LOG (GNUNET_ERROR_TYPE_INFO,
- "<== %s ( 0x%08X %4u) on chan %s (%p) %s [%5u]\n",
- GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY), ch->gid, 0,
- GCCH_2s (ch), ch, GC_f2s (fwd), ntohs (msg->header.size));
-
- /* 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;
- }
+ int do_log;
- GCCH_debug (ch, GNUNET_ERROR_TYPE_DEBUG);
- if ( (fwd && NULL == ch->dest) || (!fwd && NULL == ch->root) )
- {
- /* Not for us (don't destroy twice a half-open loopback channel) */
+ do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
+ "cadet-chn",
+ __FILE__, __FUNCTION__, __LINE__);
+ if (0 == do_log)
return;
- }
-
- rel = fwd ? ch->dest_rel : ch->root_rel;
- if (0 == rel->n_recv)
- {
- send_destroy (ch, GNUNET_YES);
- GCCH_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
-GCCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
- struct CadetChannel *ch, int fwd,
- void *existing_copy)
-{
- struct CadetChannelQueue *chq;
- uint32_t data_id;
- uint16_t type;
- uint16_t size;
- char info[32];
-
- type = ntohs (message->type);
- size = ntohs (message->size);
-
- data_id = 0;
- switch (type)
- {
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA:
- {
- struct GNUNET_CADET_ChannelAppDataMessage *data_msg;
- struct GNUNET_MessageHeader *payload_msg;
- uint16_t payload_type;
-
- data_msg = (struct GNUNET_CADET_ChannelAppDataMessage *) message;
- data_id = ntohl (data_msg->mid);
- payload_msg = (struct GNUNET_MessageHeader *) &data_msg[1];
- payload_type = ntohs (payload_msg->type);
- strncpy (info, GC_m2s (payload_type), 31);
- info[31] = '\0';
- break;
- }
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK:
- {
- struct GNUNET_CADET_ChannelDataAckMessage *ack_msg;
- ack_msg = (struct GNUNET_CADET_ChannelDataAckMessage *) message;
- data_id = ntohl (ack_msg->mid);
- SPRINTF (info, "0x%010lX",
- (unsigned long int) ack_msg->futures);
- break;
- }
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN:
- {
- struct GNUNET_CADET_ChannelOpenMessage *cc_msg;
- cc_msg = (struct GNUNET_CADET_ChannelOpenMessage *) message;
- SPRINTF (info, " 0x%08X", ntohl (cc_msg->ctn.cn));
- break;
- }
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
- {
- struct GNUNET_CADET_ChannelManageMessage *m_msg;
- m_msg = (struct GNUNET_CADET_ChannelManageMessage *) message;
- SPRINTF (info, " 0x%08X", ntohl (m_msg->ctn.cn));
- break;
- }
- default:
- info[0] = '\0';
- }
- LOG (GNUNET_ERROR_TYPE_INFO,
- "==> %s (%12s %4u) on chan %s (%p) %s [%5u]\n",
- GC_m2s (type), info, data_id,
- GCCH_2s (ch), ch, GC_f2s (fwd), size);
- if (GCT_is_loopback (ch->t))
+ if (NULL == ch)
{
- handle_loopback (ch, message, fwd);
+ LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n");
return;
}
-
- switch (type)
+ LOG2 (level,
+ "CHN %s:%X (%p)\n",
+ GCT_2s (ch->t),
+ ch->ctn,
+ ch);
+ if (NULL != ch->owner)
{
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA:
- 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 = GCT_send_prebuilt_message (message, ch->t, NULL,
- GNUNET_YES,
- &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_APP_DATA_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK:
- 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)
- {
- GCT_cancel (chq->rel->uniq->tq);
- /* ch_message_sent is called, freeing and NULLing uniq */
- GNUNET_break (NULL == chq->rel->uniq);
- }
- else
- {
- GNUNET_break (0);
- GNUNET_free (chq->rel->uniq);
- }
- }
-
- chq->rel->uniq = chq;
- chq->tq = GCT_send_prebuilt_message (message, ch->t, NULL, GNUNET_YES,
- &ch_message_sent, chq);
- if (NULL == chq->tq)
- {
- GNUNET_break (0);
- chq->rel->uniq = NULL;
- GCT_debug (ch->t, GNUNET_ERROR_TYPE_ERROR);
- GNUNET_free (chq);
- chq = NULL;
- return;
- }
- break;
-
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED:
- fire_and_forget (message, ch, GNUNET_YES);
- break;
-
-
- default:
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_WARNING, "type %s unknown!\n", GC_m2s (type));
- fire_and_forget (message, ch, GNUNET_YES);
+ LOG2 (level,
+ "CHN origin %s ready %s local-id: %u\n",
+ GSC_2s (ch->owner->c),
+ ch->owner->client_ready ? "YES" : "NO",
+ ntohl (ch->owner->ccn.channel_of_client));
}
+ if (NULL != ch->dest)
+ {
+ LOG2 (level,
+ "CHN destination %s ready %s local-id: %u\n",
+ GSC_2s (ch->dest->c),
+ ch->dest->client_ready ? "YES" : "NO",
+ ntohl (ch->dest->ccn.channel_of_client));
+ }
+ LOG2 (level,
+ "CHN Message IDs recv: %d (%LLX), send: %d\n",
+ ntohl (ch->mid_recv.mid),
+ (unsigned long long) ch->mid_futures,
+ ntohl (ch->mid_send.mid));
}
-/**
- * Get the static string for identification of the channel.
- *
- * @param ch Channel.
- *
- * @return Static string with the channel IDs.
- */
-const char *
-GCCH_2s (const struct CadetChannel *ch)
-{
- static char buf[64];
-
- if (NULL == ch)
- return "(NULL Channel)";
- SPRINTF (buf,
- "%s:%s gid:%X (%X / %X)",
- GCT_2s (ch->t),
- GNUNET_h2s (&ch->port),
- ntohl (ch->gid.cn),
- ntohl (ch->lid_root.channel_of_client),
- ntohl (ch->lid_dest.channel_of_client));
-
- return buf;
-}
+/* end of gnunet-service-cadet-new_channel.c */
diff --git a/src/cadet/gnunet-service-cadet_channel.h b/src/cadet/gnunet-service-cadet_channel.h
index 9d48932697..a3ef9a06d7 100644
--- a/src/cadet/gnunet-service-cadet_channel.h
+++ b/src/cadet/gnunet-service-cadet_channel.h
@@ -1,6 +1,7 @@
+
/*
This file is part of GNUnet.
- Copyright (C) 2013 GNUnet e.V.
+ Copyright (C) 2001-2017 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
@@ -20,344 +21,242 @@
/**
* @file cadet/gnunet-service-cadet_channel.h
- * @brief cadet service; dealing with end-to-end channels
+ * @brief GNUnet CADET service with encryption
* @author Bartlomiej Polot
- *
- * All functions in this file should use the prefix GMCH (Gnunet Cadet CHannel)
+ * @author Christian Grothoff
*/
-
#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 "gnunet-service-cadet.h"
+#include "gnunet-service-cadet_peer.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
-GCCH_destroy (struct CadetChannel *ch);
/**
- * Get the channel's public ID.
- *
- * @param ch Channel.
- *
- * @return ID used to identify the channel with the remote peer.
+ * A channel is a bidirectional connection between two CADET
+ * clients. Communiation can be reliable, unreliable, in-order
+ * or out-of-order. One client is the "local" client, this
+ * one initiated the connection. The other client is the
+ * "incoming" client, this one listened on a port to accept
+ * the connection from the "local" client.
*/
-struct GNUNET_CADET_ChannelTunnelNumber
-GCCH_get_id (const struct CadetChannel *ch);
-
-
-/**
- * Get the channel tunnel.
- *
- * @param ch Channel to get the tunnel from.
- *
- * @return tunnel of the channel.
- */
-struct CadetTunnel *
-GCCH_get_tunnel (const struct CadetChannel *ch);
+struct CadetChannel;
/**
- * Get free buffer space towards the client on a specific channel.
+ * Get the static string for identification of the channel.
*
* @param ch Channel.
- * @param fwd Is query about FWD traffic?
*
- * @return Free buffer space [0 - 64]
+ * @return Static string with the channel IDs.
*/
-unsigned int
-GCCH_get_buffer (struct CadetChannel *ch, int fwd);
+const char *
+GCCH_2s (const struct CadetChannel *ch);
/**
- * Get flow control status of end point: is client allow to send?
+ * Log channel info.
*
* @param ch Channel.
- * @param fwd Is query about FWD traffic? (Request root status).
- *
- * @return #GNUNET_YES if client is allowed to send us data.
+ * @param level Debug level to use.
*/
-int
-GCCH_get_allowed (struct CadetChannel *ch, int fwd);
+void
+GCCH_debug (struct CadetChannel *ch,
+ enum GNUNET_ErrorType level);
/**
- * Is the root client for this channel on this peer?
+ * Get the channel's public ID.
*
* @param ch Channel.
- * @param fwd Is this for fwd traffic?
*
- * @return #GNUNET_YES in case it is.
+ * @return ID used to identify the channel with the remote peer.
*/
-int
-GCCH_is_origin (struct CadetChannel *ch, int fwd);
+struct GNUNET_CADET_ChannelTunnelNumber
+GCCH_get_id (const struct CadetChannel *ch);
-/**
- * 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
-GCCH_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)
+ * Create a new channel.
+ *
+ * @param owner local client owning the channel
+ * @param owner_id local chid of this channel at the @a owner
+ * @param destination peer to which we should build the channel
+ * @param port desired port at @a destination
+ * @param options options for the channel
+ * @return handle to the new channel
*/
-void
-GCCH_send_data_ack (struct CadetChannel *ch, int fwd);
+struct CadetChannel *
+GCCH_channel_local_new (struct CadetClient *owner,
+ struct GNUNET_CADET_ClientChannelNumber owner_id,
+ struct CadetPeer *destination,
+ const struct GNUNET_HashCode *port,
+ uint32_t options);
-/**
- * Notify the destination client that a new incoming channel was created.
- *
- * @param ch Channel that was created.
- */
-void
-GCCH_send_create (struct CadetChannel *ch);
/**
- * Allow a client to send us more data, in case it was choked.
+ * A client is bound to the port that we have a channel
+ * open to. Send the acknowledgement for the connection
+ * request and establish the link with the client.
*
- * @param ch Channel.
- * @param fwd Is this about FWD traffic? (Root client).
+ * @param ch open incoming channel
+ * @param c client listening on the respective port
*/
void
-GCCH_allow_client (struct CadetChannel *ch, int fwd);
+GCCH_bind (struct CadetChannel *ch,
+ struct CadetClient *c);
-/**
- * Log channel info.
- *
- * @param ch Channel.
- * @param level Debug level to use.
- */
-void
-GCCH_debug (struct CadetChannel *ch, enum GNUNET_ErrorType level);
/**
- * Handle an ACK given by a client.
+ * Destroy locally created channel. Called by the
+ * local client, so no need to tell the 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)
+ * @param ch channel to destroy
+ * @param c client that caused the destruction
+ * @param ccn client number of the client @a c
*/
void
-GCCH_handle_local_ack (struct CadetChannel *ch, int fwd);
+GCCH_channel_local_destroy (struct CadetChannel *ch,
+ struct CadetClient *c,
+ struct GNUNET_CADET_ClientChannelNumber ccn);
-/**
- * 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 fwd Is this a FWD data?
- * @param message Data message.
- * @param size Size of data.
- *
- * @return GNUNET_OK if everything goes well, GNUNET_SYSERR in case of en error.
- */
-int
-GCCH_handle_local_data (struct CadetChannel *ch,
- struct CadetClient *c, int fwd,
- const struct GNUNET_MessageHeader *message,
- size_t size);
/**
- * 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?
+ * Function called once and only once after a channel was bound
+ * to its tunnel via #GCT_add_channel() is ready for transmission.
+ * Note that this is only the case for channels that this peer
+ * initiates, as for incoming channels we assume that they are
+ * ready for transmission immediately upon receiving the open
+ * message. Used to bootstrap the #GCT_send() process.
+ *
+ * @param ch the channel for which the tunnel is now ready
*/
void
-GCCH_handle_local_destroy (struct CadetChannel *ch,
- struct CadetClient *c,
- int is_root);
+GCCH_tunnel_up (struct CadetChannel *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.
+ * Create a new channel based on a request coming in over the network.
+ *
+ * @param t tunnel to the remote peer
+ * @param chid identifier of this channel in the tunnel
+ * @param origin peer to who initiated the channel
+ * @param port desired local port
+ * @param options options for the channel
+ * @return handle to the new channel
*/
-int
-GCCH_handle_local_create (struct CadetClient *c,
- struct GNUNET_CADET_LocalChannelCreateMessage *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
-GCCH_handle_data (struct CadetChannel *ch,
- const struct GNUNET_CADET_ChannelAppDataMessage *msg,
- int fwd);
+struct CadetChannel *
+GCCH_channel_incoming_new (struct CadetTunnel *t,
+ struct GNUNET_CADET_ChannelTunnelNumber chid,
+ const struct GNUNET_HashCode *port,
+ uint32_t options);
/**
- * Handler for cadet network traffic end-to-end ACKs.
+ * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
+ * this channel. If the binding was successful, (re)transmit the
+ * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
*
- * @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)
+ * @param ch channel that got the duplicate open
+ * @param cti identifier of the connection that delivered the message
*/
void
-GCCH_handle_data_ack (struct CadetChannel *ch,
- const struct GNUNET_CADET_ChannelDataAckMessage *msg,
- int fwd);
+GCCH_handle_duplicate_open (struct CadetChannel *ch,
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
-/**
- * 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 *
-GCCH_handle_create (struct CadetTunnel *t,
- const struct GNUNET_CADET_ChannelOpenMessage *msg);
-
/**
- * Handler for channel NACK messages.
+ * We got payload data for a channel. Pass it on to the client.
*
- * NACK messages always go dest -> root, no need for 'fwd' or 'msg' parameter.
- *
- * @param ch Channel.
+ * @param ch channel that got data
+ * @param cti identifier of the connection that delivered the message
+ * @param msg message that was received
*/
void
-GCCH_handle_nack (struct CadetChannel *ch);
+GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+ const struct GNUNET_CADET_ChannelAppDataMessage *msg);
/**
- * Handler for channel ack messages.
+ * We got an acknowledgement for payload data for a channel.
+ * Possibly resume transmissions.
*
- * @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)
+ * @param ch channel that got the ack
+ * @param cti identifier of the connection that delivered the message
+ * @param ack details about what was received
*/
void
-GCCH_handle_ack (struct CadetChannel *ch,
- const struct GNUNET_CADET_ChannelManageMessage *msg,
- int fwd);
+GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+ const struct GNUNET_CADET_ChannelDataAckMessage *ack);
/**
- * Handler for channel destroy messages.
+ * We got an acknowledgement for the creation of the channel
+ * (the port is open on the other side). Begin transmissions.
*
- * @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)
+ * @param ch channel to destroy
+ * @param cti identifier of the connection that delivered the message,
+ * NULL if the ACK was inferred because we got payload or are on loopback
*/
void
-GCCH_handle_destroy (struct CadetChannel *ch,
- const struct GNUNET_CADET_ChannelManageMessage *msg,
- int fwd);
+GCCH_handle_channel_open_ack (struct CadetChannel *ch,
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
/**
- * Sends an already built message on a channel.
+ * Destroy channel, based on the other peer closing the
+ * connection. Also needs to remove this channel from
+ * the tunnel.
*
- * If the channel is on a loopback tunnel, notifies the appropriate destination
- * client locally.
+ * FIXME: need to make it possible to defer destruction until we have
+ * received all messages up to the destroy, and right now the destroy
+ * message (and this API) fails to give is the information we need!
*
- * On a normal channel passes the message to the tunnel for encryption and
- * sending on a connection.
+ * FIXME: also need to know if the other peer got a destroy from
+ * us before!
*
- * 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.
+ * @param ch channel to destroy
+ * @param cti identifier of the connection that delivered the message,
+ * NULL during shutdown
*/
void
-GCCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
- struct CadetChannel *ch, int fwd,
- void *existing_copy);
+GCCH_handle_remote_destroy (struct CadetChannel *ch,
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
/**
- * Get the static string for identification of the channel.
+ * Handle data given by a client.
*
- * @param ch Channel.i
+ * 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.
*
- * @return Static string with the channel IDs.
+ * @param ch Channel.
+ * @param sender_ccn ccn of the sender
+ * @param buf payload to transmit.
+ * @param buf_len number of bytes in @a buf
+ * @return #GNUNET_OK if everything goes well,
+ * #GNUNET_SYSERR in case of an error.
*/
-const char *
-GCCH_2s (const struct CadetChannel *ch);
-
-
+int
+GCCH_handle_local_data (struct CadetChannel *ch,
+ struct GNUNET_CADET_ClientChannelNumber sender_ccn,
+ const char *buf,
+ size_t buf_len);
-#if 0 /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
+/**
+ * Handle ACK from client on local channel.
+ *
+ * @param ch channel to destroy
+ * @param client_ccn ccn of the client sending the ack
+ */
+void
+GCCH_handle_local_ack (struct CadetChannel *ch,
+ struct GNUNET_CADET_ClientChannelNumber client_ccn);
-/* 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
index 2d5087f817..7b66f61a26 100644
--- a/src/cadet/gnunet-service-cadet_connection.c
+++ b/src/cadet/gnunet-service-cadet_connection.c
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet.
- Copyright (C) 2001-2015 GNUnet e.V.
+ Copyright (C) 2001-2017 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
@@ -17,242 +17,126 @@
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
+
/**
* @file cadet/gnunet-service-cadet_connection.c
- * @brief GNUnet CADET service connection handling
+ * @brief management of CORE-level end-to-end connections; establishes
+ * end-to-end routes and transmits messages along the route
* @author Bartlomiej Polot
+ * @author Christian Grothoff
*/
#include "platform.h"
-#include "gnunet_util_lib.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_channel.h"
+#include "gnunet-service-cadet_paths.h"
+#include "gnunet-service-cadet_tunnels.h"
+#include "gnunet_cadet_service.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"
-
-
-/**
- * Should we run somewhat expensive checks on our invariants?
- */
-#define CHECK_INVARIANTS 0
-
-
-#define LOG(level, ...) GNUNET_log_from (level,"cadet-con",__VA_ARGS__)
-#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-con",__VA_ARGS__)
-
-
-#define CADET_MAX_POLL_TIME GNUNET_TIME_relative_multiply (\
- GNUNET_TIME_UNIT_MINUTES,\
- 10)
-#define AVG_MSGS 32
-
-
-/******************************************************************************/
-/******************************** STRUCTS **********************************/
-/******************************************************************************/
-
-/**
- * Handle for messages queued but not yet sent.
- */
-struct CadetConnectionQueue
-{
- struct CadetConnectionQueue *next;
- struct CadetConnectionQueue *prev;
- /**
- * Peer queue handle, to cancel if necessary.
- */
- struct CadetPeerQueue *peer_q;
-
- /**
- * Continuation to call once sent.
- */
- GCC_sent cont;
-
- /**
- * Closure for @e cont.
- */
- void *cont_cls;
-
- /**
- * Was this a forced message? (Do not account for it)
- */
- int forced;
-};
+#define LOG(level, ...) GNUNET_log_from(level,"cadet-con",__VA_ARGS__)
/**
- * Struct to encapsulate all the Flow Control information to a peer to which
- * we are directly connected (on a core level).
+ * All the states a connection can be in.
*/
-struct CadetFlowControl
+enum CadetConnectionState
{
/**
- * Connection this controls.
- */
- struct CadetConnection *c;
-
- struct CadetConnectionQueue *q_head;
- struct CadetConnectionQueue *q_tail;
-
- /**
- * How many messages are in the queue on this connection.
- */
- unsigned int queue_n;
-
- /**
- * How many messages do we accept in the queue.
- * If 0, the connection is broken in this direction (next hop disconnected).
- */
- unsigned int queue_max;
-
- /**
- * ID of the next packet to send.
- */
- struct CadetEncryptedMessageIdentifier next_pid;
-
- /**
- * ID of the last packet sent towards the peer.
- */
- struct CadetEncryptedMessageIdentifier last_pid_sent;
-
- /**
- * ID of the last packet received from the peer.
- */
- struct CadetEncryptedMessageIdentifier last_pid_recv;
-
- /**
- * Bitmap of past 32 messages received:
- * - LSB being @c last_pid_recv.
- * - MSB being @c last_pid_recv - 31 (mod UINTMAX).
- */
- uint32_t recv_bitmap;
-
- /**
- * Last ACK sent to the peer (peer is not allowed to send
- * messages with PIDs higher than this value).
+ * Uninitialized status, we have not yet even gotten the message queue.
*/
- struct CadetEncryptedMessageIdentifier last_ack_sent;
+ CADET_CONNECTION_NEW,
/**
- * Last ACK sent towards the origin (for traffic towards leaf node).
+ * Connection create message in queue, awaiting transmission by CORE.
*/
- struct CadetEncryptedMessageIdentifier last_ack_recv;
+ CADET_CONNECTION_SENDING_CREATE,
/**
- * Task to poll the peer in case of a lost ACK causes stall.
+ * Connection create message sent, waiting for ACK.
*/
- struct GNUNET_SCHEDULER_Task *poll_task;
+ CADET_CONNECTION_SENT,
/**
- * How frequently to poll for ACKs.
+ * We are an inbound connection, and received a CREATE. Need to
+ * send an CREATE_ACK back.
*/
- struct GNUNET_TIME_Relative poll_time;
+ CADET_CONNECTION_CREATE_RECEIVED,
/**
- * Queued poll message, to cancel if not necessary anymore (got ACK).
+ * Connection confirmed, ready to carry traffic.
*/
- struct CadetConnectionQueue *poll_msg;
+ CADET_CONNECTION_READY
- /**
- * 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.
+ * Low-level connection to a destination.
*/
-struct CadetConnectionPerformance
+struct CadetConnection
{
- /**
- * 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.
+ * ID of the connection.
*/
- uint16_t idx;
-};
-
+ struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
-/**
- * Struct containing all information regarding a connection to a peer.
- */
-struct CadetConnection
-{
/**
- * Tunnel this connection is part of.
+ * To which peer does this connection go?
*/
- struct CadetTunnel *t;
+ struct CadetPeer *destination;
/**
- * Flow control information for traffic fwd.
+ * Which tunnel is using this connection?
*/
- struct CadetFlowControl fwd_fc;
+ struct CadetTConnection *ct;
/**
- * Flow control information for traffic bck.
+ * Path we are using to our destination.
*/
- struct CadetFlowControl bck_fc;
+ struct CadetPeerPath *path;
/**
- * Measure connection performance on the endpoint.
+ * Pending message, NULL if we are ready to transmit.
*/
- struct CadetConnectionPerformance *perf;
+ struct GNUNET_MQ_Envelope *env;
/**
- * ID of the connection.
+ * Handle for calling #GCP_request_mq_cancel() once we are finished.
*/
- struct GNUNET_CADET_ConnectionTunnelIdentifier id;
+ struct GCP_MessageQueueManager *mq_man;
/**
- * 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.
+ * Task for connection maintenance.
*/
- struct CadetPeerPath *path;
+ struct GNUNET_SCHEDULER_Task *task;
/**
- * Task to keep the used paths alive at the owner,
- * time tunnel out on all the other peers.
+ * Queue entry for keepalive messages.
*/
- struct GNUNET_SCHEDULER_Task *fwd_maintenance_task;
+ struct CadetTunnelQueueEntry *keepalive_qe;
/**
- * Task to keep the used paths alive at the destination,
- * time tunnel out on all the other peers.
+ * Function to call once we are ready to transmit.
*/
- struct GNUNET_SCHEDULER_Task *bck_maintenance_task;
+ GCC_ReadyCallback ready_cb;
/**
- * Queue handle for maintainance traffic. One handle for FWD and BCK since
- * one peer never needs to maintain both directions (no loopback connections).
+ * Closure for @e ready_cb.
*/
- struct CadetPeerQueue *maintenance_q;
+ void *ready_cb_cls;
/**
- * Should equal #get_next_hop(), or NULL if that peer disconnected.
+ * How long do we wait before we try again with a CREATE message?
*/
- struct CadetPeer *next_peer;
+ struct GNUNET_TIME_Relative retry_delay;
/**
- * Should equal #get_prev_hop(), or NULL if that peer disconnected.
+ * Performance metrics for this connection.
*/
- struct CadetPeer *prev_peer;
+ struct CadetConnectionMetrics metrics;
/**
* State of the connection.
@@ -260,221 +144,36 @@ struct CadetConnection
enum CadetConnectionState state;
/**
- * Position of the local peer in the path.
+ * Options for the route, control buffering.
*/
- unsigned int own_pos;
+ enum GNUNET_CADET_ChannelOption options;
/**
- * Pending message count.
+ * How many latency observations did we make for this connection?
*/
- unsigned int pending_messages;
+ unsigned int latency_datapoints;
/**
- * Destroy flag:
- * - if 0, connection in use.
- * - if 1, destroy on last message.
- * - if 2, connection is being destroyed don't re-enter.
+ * Offset of our @e destination in @e path.
*/
- int destroy;
+ unsigned int off;
/**
- * In-connection-map flag. Sometimes, when @e destroy is set but
- * actual destruction is delayed to enable us to finish processing
- * queues (i.e. in the direction that is still working), we remove
- * the connection from the map to prevent it from still being
- * found (and used) by accident. This flag is set to #GNUNET_YES
- * for a connection that is not in the #connections map. Should
- * only be #GNUNET_YES if #destroy is also non-zero.
+ * Are we ready to transmit via @e mq_man right now?
*/
- int was_removed;
+ int mqm_ready;
- /**
- * Counter to do exponential backoff when creating a connection (max 64).
- */
- unsigned short create_retry;
-
- /**
- * Task to check if connection has duplicates.
- */
- struct GNUNET_SCHEDULER_Task *check_duplicates_task;
};
-/******************************************************************************/
-/******************************* 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_MultiShortmap *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",
- ntohl (fc->last_pid_recv.pid),
- ntohl (fc->last_ack_sent.pid));
- 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_INFO, "DEBUG NULL CONNECTION\n");
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s:%X\n",
- peer2s (c->t->peer), GCC_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 *
-GCC_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";
- case CADET_CONNECTION_BROKEN:
- return "CADET_CONNECTION_BROKEN";
- default:
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_ERROR, " conn state %u unknown!\n", s);
- return "CADET_CONNECTION_STATE_ERROR";
- }
-}
-
-
/**
- * Initialize a Flow Control structure to the initial state.
+ * Lookup a connection by its identifier.
*
- * @param fc Flow Control structure to initialize.
+ * @param cid identifier to resolve
+ * @return NULL if connection was not found
*/
-static void
-fc_init (struct CadetFlowControl *fc)
-{
- fc->next_pid.pid = 0;
- fc->last_pid_sent.pid = htonl (UINT32_MAX);
- fc->last_pid_recv.pid = htonl (UINT32_MAX);
- fc->last_ack_sent.pid = (uint32_t) 0;
- fc->last_ack_recv.pid = (uint32_t) 0;
- fc->poll_task = NULL;
- 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.
- *
- * @return conntection with the given ID @cid or NULL if not found.
- */
-static struct CadetConnection *
-connection_get (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
+struct CadetConnection *
+GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
{
return GNUNET_CONTAINER_multishortmap_get (connections,
&cid->connection_of_tunnel);
@@ -482,3232 +181,911 @@ connection_get (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
/**
- * Change the connection state. Cannot change a connection marked as destroyed.
+ * Update the connection state. Also triggers the necessary
+ * MQM notifications.
*
- * @param c Connection to change.
- * @param state New state to set.
+ * @param cc connection to update the state for
+ * @param new_state new state for @a cc
+ * @param new_mqm_ready new `mqm_ready` state for @a cc
*/
static void
-connection_change_state (struct CadetConnection* c,
- enum CadetConnectionState state)
+update_state (struct CadetConnection *cc,
+ enum CadetConnectionState new_state,
+ int new_mqm_ready)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Connection %s state %s -> %s\n",
- GCC_2s (c), GCC_state2s (c->state), GCC_state2s (state));
- if (CADET_CONNECTION_DESTROYED <= c->state) /* Destroyed or broken. */
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "state not changing anymore\n");
- return;
- }
- c->state = state;
- if (CADET_CONNECTION_READY == state)
- c->create_retry = 1;
-}
-
+ int old_ready;
+ int new_ready;
-/**
- * Mark a connection as "destroyed", to send all pending traffic and freeing
- * all associated resources, without accepting new status changes on it.
- *
- * @param c Connection to mark as destroyed.
- */
-static void
-mark_destroyed (struct CadetConnection *c)
-{
- c->destroy = GNUNET_YES;
- connection_change_state (c, CADET_CONNECTION_DESTROYED);
+ if ( (new_state == cc->state) &&
+ (new_mqm_ready == cc->mqm_ready) )
+ return; /* no change, nothing to do */
+ old_ready = ( (CADET_CONNECTION_READY == cc->state) &&
+ (GNUNET_YES == cc->mqm_ready) );
+ new_ready = ( (CADET_CONNECTION_READY == new_state) &&
+ (GNUNET_YES == new_mqm_ready) );
+ cc->state = new_state;
+ cc->mqm_ready = new_mqm_ready;
+ if (old_ready != new_ready)
+ cc->ready_cb (cc->ready_cb_cls,
+ new_ready);
}
/**
- * 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).
- */
-static void
-send_poll (void *cls);
-
-
-/**
- * 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).
+ * Destroy a connection, part of the internal implementation. Called
+ * only from #GCC_destroy_from_core() or #GCC_destroy_from_tunnel().
*
- * @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.
+ * @param cc connection to destroy
*/
static void
-send_ack (struct CadetConnection *c,
- unsigned int buffer,
- int fwd,
- int force)
+GCC_destroy (struct CadetConnection *cc)
{
- static struct CadetEncryptedMessageIdentifier zero;
- struct CadetFlowControl *next_fc;
- struct CadetFlowControl *prev_fc;
- struct GNUNET_CADET_ConnectionEncryptedAckMessage msg;
- struct CadetEncryptedMessageIdentifier ack_cemi;
- int delta;
-
- GCC_check_connections ();
- GNUNET_assert (GNUNET_NO == GCC_is_origin (c, fwd));
-
- next_fc = fwd ? &c->fwd_fc : &c->bck_fc;
- prev_fc = fwd ? &c->bck_fc : &c->fwd_fc;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "send %s ack on %s\n",
- GC_f2s (fwd), GCC_2s (c));
-
- /* Check if we need to transmit the ACK. */
- delta = ntohl (prev_fc->last_ack_sent.pid) - ntohl (prev_fc->last_pid_recv.pid);
- if (3 < delta && buffer < delta && GNUNET_NO == force)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending ACK, delta > 3\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " last pid recv: %u, last ack sent: %u\n",
- ntohl (prev_fc->last_pid_recv.pid),
- ntohl (prev_fc->last_ack_sent.pid));
- GCC_check_connections ();
- return;
- }
-
- /* Ok, ACK might be necessary, what PID to ACK? */
- ack_cemi.pid = htonl (ntohl (prev_fc->last_pid_recv.pid) + buffer);
LOG (GNUNET_ERROR_TYPE_DEBUG,
- " ACK %u, last PID %u, last ACK %u, qmax %u, q %u\n",
- ntohl (ack_cemi.pid),
- ntohl (prev_fc->last_pid_recv.pid),
- ntohl (prev_fc->last_ack_sent.pid),
- next_fc->queue_max, next_fc->queue_n);
- if ( (ack_cemi.pid == prev_fc->last_ack_sent.pid) &&
- (GNUNET_NO == force) )
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending FWD ACK, not needed\n");
- GCC_check_connections ();
- return;
- }
-
- /* Check if message is already in queue */
- if (NULL != prev_fc->ack_msg)
- {
- if (GC_is_pid_bigger (ntohl (ack_cemi.pid),
- ntohl (prev_fc->last_ack_sent.pid)))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " canceling old ACK\n");
- GCC_cancel (prev_fc->ack_msg);
- /* GCC_cancel triggers ack_sent(), which clears fc->ack_msg */
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " same ACK already in queue\n");
- GCC_check_connections ();
- return;
- }
- }
- GNUNET_break (GC_is_pid_bigger (ntohl (ack_cemi.pid),
- ntohl (prev_fc->last_ack_sent.pid)));
- prev_fc->last_ack_sent = ack_cemi;
-
- /* Build ACK message and send on conn */
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK);
- msg.cemi_max = ack_cemi;
- msg.cid = c->id;
-
- prev_fc->ack_msg = GCC_send_prebuilt_message (&msg.header,
- UINT16_MAX,
- zero,
- c,
- !fwd,
- GNUNET_YES,
- NULL, NULL);
- GNUNET_assert (NULL != prev_fc->ack_msg);
- GCC_check_connections ();
-}
-
-
-/**
- * Update performance information if we are a connection's endpoint.
- *
- * @param c Connection to update.
- * @param wait How much time did we wait to send the last message.
- * @param size Size of the last message.
- */
-static void
-update_perf (struct CadetConnection *c,
- struct GNUNET_TIME_Relative wait,
- uint16_t size)
-{
- struct CadetConnectionPerformance *p;
- double usecsperbyte;
-
- 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;
-}
-
-
-/**
- * Callback called when a connection queued message is sent.
- *
- * Calculates the average time and connection packet tracking.
- *
- * @param cls Closure (ConnectionQueue Handle), can be NULL.
- * @param c Connection this message was on.
- * @param fwd Was this a FWD going message?
- * @param sent Was it really sent? (Could have been canceled)
- * @param type Type of message sent.
- * @param payload_type Type of payload, if applicable.
- * @param pid Message ID, or 0 if not applicable (create, destroy, etc).
- * @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 fwd,
- int sent,
- uint16_t type,
- uint16_t payload_type,
- struct CadetEncryptedMessageIdentifier pid,
- size_t size,
- struct GNUNET_TIME_Relative wait)
-{
- struct CadetConnectionQueue *q = cls;
- struct CadetFlowControl *fc;
- int forced;
-
- GCC_check_connections ();
- LOG (GNUNET_ERROR_TYPE_INFO,
- ">>> %s (%s %4u) on conn %s (%p) %s [%5u] in queue %s\n",
- GC_m2s (type), GC_m2s (payload_type),
- ntohl (pid.pid),
- GCC_2s (c),
- c,
- GC_f2s (fwd), size,
- GNUNET_STRINGS_relative_time_to_string (wait, GNUNET_YES));
-
- /* If c is NULL, nothing to update. */
- if (NULL == c)
- {
- if (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",
- GC_m2s (type));
- }
- GCC_check_connections ();
- return;
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " %ssent %s %s pid %u\n",
- sent ? "" : "not ", GC_f2s (fwd),
- GC_m2s (type), GC_m2s (payload_type),
- ntohl (pid.pid));
- GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG);
-
- /* Update flow control info. */
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
-
- if (NULL != q)
+ "Destroying %s\n",
+ GCC_2s (cc));
+ if (NULL != cc->mq_man)
{
- GNUNET_CONTAINER_DLL_remove (fc->q_head, fc->q_tail, 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);
+ GCP_request_mq_cancel (cc->mq_man,
+ NULL);
+ cc->mq_man = NULL;
}
- else /* CONN_CREATE or CONN_ACK */
+ if (NULL != cc->task)
{
- GNUNET_assert (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED != type);
- forced = GNUNET_YES;
+ GNUNET_SCHEDULER_cancel (cc->task);
+ cc->task = NULL;
}
-
- 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) )
+ if (NULL != cc->keepalive_qe)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "! destroying connection!\n");
- GCC_destroy (c);
- GCC_check_connections ();
- return;
+ GCT_send_cancel (cc->keepalive_qe);
+ cc->keepalive_qe = NULL;
}
-
- /* 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_CREATE_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_TUNNEL_ENCRYPTED:
- if (GNUNET_YES == sent)
- {
- fc->last_pid_sent = pid;
- if (GC_is_pid_bigger (ntohl (fc->last_pid_sent.pid) + 1,
- ntohl (fc->last_ack_recv.pid)) )
- GCC_start_poll (c, fwd);
- GCC_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",
- ntohl (fc->last_pid_sent.pid));
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "! forced, Q_N not accounting pid %u\n",
- ntohl (fc->last_pid_sent.pid));
- }
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX:
- if (GNUNET_YES == sent)
- connection_reset_timeout (c, fwd);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL:
- fc->poll_msg = NULL;
- if (2 == c->destroy)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL canceled on shutdown\n");
- return;
- }
- if (0 == fc->queue_max)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL cancelled: neighbor disconnected\n");
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL sent for %s, scheduling new one!\n",
- GCC_2s (c));
- GNUNET_assert (NULL == fc->poll_task);
- fc->poll_time = GNUNET_TIME_STD_BACKOFF (fc->poll_time);
- fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time,
- &send_poll, fc);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " task %u\n", fc->poll_task);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK:
- fc->ack_msg = NULL;
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
- break;
-
- default:
- LOG (GNUNET_ERROR_TYPE_ERROR, "%s unknown\n", GC_m2s (type));
- GNUNET_break (0);
- break;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "! message sent!\n");
-
- update_perf (c, wait, size);
- GCC_check_connections ();
-}
-
-
-/**
- * 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;
-
- if (NULL == c->path)
- return NULL;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " get prev hop %s [%u/%u]\n",
- GCC_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 GCP_get_short (id, GNUNET_YES);
-}
-
-
-/**
- * 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;
-
- if (NULL == c->path)
- return NULL;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " get next hop %s [%u/%u]\n",
- GCC_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 GCP_get_short (id, GNUNET_YES);
+ GCPP_del_connection (cc->path,
+ cc->off,
+ cc);
+ for (unsigned int i=0;i<cc->off;i++)
+ GCP_remove_connection (GCPP_get_peer_at_offset (cc->path,
+ i),
+ cc);
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multishortmap_remove (connections,
+ &GCC_get_id (cc)->connection_of_tunnel,
+ cc));
+ GNUNET_free (cc);
}
-/**
- * Check that the direct neighbours (previous and next hop)
- * are properly associated with this connection.
- *
- * @param c connection to check
- */
-static void
-check_neighbours (const struct CadetConnection *c)
-{
- if (NULL == c->path)
- return; /* nothing to check */
- GCP_check_connection (get_next_hop (c), c);
- GCP_check_connection (get_prev_hop (c), c);
-}
-
/**
- * Helper for #GCC_check_connections(). Calls #check_neighbours().
+ * Destroy a connection, called when the CORE layer is already done
+ * (i.e. has received a BROKEN message), but if we still have to
+ * communicate the destruction of the connection to the tunnel (if one
+ * exists).
*
- * @param cls NULL
- * @param key ignored
- * @param value the `struct CadetConnection` to check
- * @return #GNUNET_OK (continue to iterate)
- */
-static int
-check_connection (void *cls,
- const struct GNUNET_ShortHashCode *key,
- void *value)
-{
- struct CadetConnection *c = value;
-
- check_neighbours (c);
- return GNUNET_OK;
-}
-
-
-/**
- * Check invariants for all connections using #check_neighbours().
+ * @param cc connection to destroy
*/
void
-GCC_check_connections ()
-{
- if (0 == CHECK_INVARIANTS)
- return;
- if (NULL == connections)
- return;
- GNUNET_CONTAINER_multishortmap_iterate (connections,
- &check_connection,
- NULL);
-}
-
-
-/**
- * Get the hop in a connection.
- *
- * @param c Connection.
- * @param fwd Next in the FWD direction?
- *
- * @return Next peer in the connection.
- */
-static struct CadetPeer *
-get_hop (struct CadetConnection *c, int fwd)
-{
- return (fwd) ? get_next_hop (c) : get_prev_hop (c);
-}
-
-
-/**
- * Get a bit mask for a message received out-of-order.
- *
- * @param last_pid_recv Last PID we received prior to the out-of-order.
- * @param ooo_pid PID of the out-of-order message.
- */
-static uint32_t
-get_recv_bitmask (struct CadetEncryptedMessageIdentifier last_pid_recv,
- struct CadetEncryptedMessageIdentifier ooo_pid)
-{
- // FIXME: should assert that the delta is in range...
- return 1 << (ntohl (last_pid_recv.pid) - ntohl (ooo_pid.pid));
-}
-
-
-/**
- * Check is an out-of-order message is ok:
- * - at most 31 messages behind.
- * - not duplicate.
- *
- * @param last_pid_recv Last in-order PID received.
- */
-static int
-is_ooo_ok (struct CadetEncryptedMessageIdentifier last_pid_recv,
- struct CadetEncryptedMessageIdentifier ooo_pid,
- uint32_t ooo_bitmap)
-{
- uint32_t mask;
-
- if (GC_is_pid_bigger (ntohl (last_pid_recv.pid) - 31,
- ntohl (ooo_pid.pid)))
- return GNUNET_NO;
-
- mask = get_recv_bitmask (last_pid_recv,
- ooo_pid);
- if (0 != (ooo_bitmap & mask))
- return GNUNET_NO;
-
- return GNUNET_YES;
-}
-
-
-/**
- * Is traffic coming from this sender 'FWD' traffic?
- *
- * @param c Connection to check.
- * @param sender Short 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 (sender isn't a hop in the connection).
- */
-static int
-is_fwd (const struct CadetConnection *c,
- const struct CadetPeer *sender)
-{
- GNUNET_PEER_Id id;
-
- id = GCP_get_short_id (sender);
- if (GCP_get_short_id (get_prev_hop (c)) == id)
- return GNUNET_YES;
-
- if (GCP_get_short_id (get_next_hop (c)) == id)
- return GNUNET_NO;
-
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Sends a CONNECTION ACK message in reponse to a received CONNECTION_CREATE
- * or a first CONNECTION_ACK directed to us.
- *
- * @param c 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 *c, int fwd)
-{
- static struct CadetEncryptedMessageIdentifier zero;
- struct GNUNET_CADET_ConnectionCreateAckMessage msg;
- struct CadetTunnel *t;
- const uint16_t size = sizeof (struct GNUNET_CADET_ConnectionCreateAckMessage);
- const uint16_t type = GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK;
-
- GCC_check_connections ();
- t = c->t;
- LOG (GNUNET_ERROR_TYPE_INFO,
- "==> %s ({ C %s ACK} 0) on conn %s (%p) %s [%5u]\n",
- GC_m2s (type), GC_f2s (!fwd), GCC_2s (c), c, GC_f2s (fwd), size);
-
- msg.header.size = htons (size);
- msg.header.type = htons (type);
- msg.reserved = htonl (0);
- msg.cid = c->id;
-
- GNUNET_assert (NULL == c->maintenance_q);
- c->maintenance_q = GCP_send (get_hop (c, fwd),
- &msg.header,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK,
- zero,
- c,
- fwd,
- &conn_message_sent, NULL);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %p %u (conn`ACK)\n",
- c, c->pending_messages);
- c->pending_messages++;
-
- if (CADET_TUNNEL_NEW == GCT_get_cstate (t))
- GCT_change_cstate (t, CADET_TUNNEL_WAITING);
- if (CADET_CONNECTION_READY != c->state)
- connection_change_state (c, CADET_CONNECTION_SENT);
- GCC_check_connections ();
-}
-
-
-/**
- * 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)
-{
- static struct CadetEncryptedMessageIdentifier zero;
- struct GNUNET_CADET_ConnectionBrokenMessage msg;
-
- GCC_check_connections ();
- msg.header.size = htons (sizeof (struct GNUNET_CADET_ConnectionBrokenMessage));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
- msg.cid = c->id;
- msg.reserved = htonl (0);
- msg.peer1 = *id1;
- msg.peer2 = *id2;
- (void) GCC_send_prebuilt_message (&msg.header,
- UINT16_MAX,
- zero,
- c,
- fwd,
- GNUNET_YES,
- NULL, NULL);
- GCC_check_connections ();
-}
-
-
-/**
- * Send a notification that a connection is broken, when a connection
- * isn't even known to the local peer or soon to be destroyed.
- *
- * @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 neighbor Peer to notify (neighbor who sent the connection).
- */
-static void
-send_broken_unknown (const struct GNUNET_CADET_ConnectionTunnelIdentifier *connection_id,
- const struct GNUNET_PeerIdentity *id1,
- const struct GNUNET_PeerIdentity *id2,
- struct CadetPeer *neighbor)
-{
- static struct CadetEncryptedMessageIdentifier zero;
- struct GNUNET_CADET_ConnectionBrokenMessage msg;
-
- GCC_check_connections ();
- LOG (GNUNET_ERROR_TYPE_INFO, "--> BROKEN on unknown connection %s\n",
- GNUNET_sh2s (&connection_id->connection_of_tunnel));
-
- msg.header.size = htons (sizeof (struct GNUNET_CADET_ConnectionBrokenMessage));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
- msg.cid = *connection_id;
- msg.reserved = htonl (0);
- msg.peer1 = *id1;
- if (NULL != id2)
- msg.peer2 = *id2;
- else
- memset (&msg.peer2, 0, sizeof (msg.peer2));
- GNUNET_assert (NULL != GCP_send (neighbor,
- &msg.header,
- UINT16_MAX,
- zero,
- NULL,
- GNUNET_SYSERR, /* connection, fwd */
- NULL, NULL)); /* continuation */
- GCC_check_connections ();
-}
-
-
-/**
- * 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)
+GCC_destroy_without_core (struct CadetConnection *cc)
{
- struct GNUNET_MessageHeader msg;
- struct CadetFlowControl *fc;
- int tunnel_ready;
-
- GCC_check_connections ();
- LOG (GNUNET_ERROR_TYPE_INFO,
- "keepalive %s for connection %s\n",
- GC_f2s (fwd), GCC_2s (c));
-
- GNUNET_assert (NULL != c->t);
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
- tunnel_ready = GNUNET_YES == GCT_has_queued_traffic (c->t)
- && CADET_TUNNEL_KEY_OK <= GCT_get_estate (c->t);
- if (0 < fc->queue_n || tunnel_ready)
+ if (NULL != cc->ct)
{
- LOG (GNUNET_ERROR_TYPE_INFO, "not sending keepalive, traffic in queue\n");
- return;
+ GCT_connection_lost (cc->ct);
+ cc->ct = NULL;
}
-
- 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_CHANNEL_KEEPALIVE);
-
- GNUNET_assert (NULL ==
- GCT_send_prebuilt_message (&msg, c->t, c,
- GNUNET_NO, NULL, NULL));
- GCC_check_connections ();
-}
-
-
-/**
- * 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)
- GCC_send_create (c);
- else
- send_connection_ack (c, GNUNET_NO);
+ GCC_destroy (cc);
}
/**
- * Generic connection timer management.
- * Depending on the role of the peer in the connection will send the
- * appropriate message (build or keepalive)
+ * Destroy a connection, called if the tunnel association with the
+ * connection was already broken, but we still need to notify the CORE
+ * layer about the breakage.
*
- * @param c Conncetion to maintain.
- * @param fwd Is FWD?
+ * @param cc connection to destroy
*/
-static void
-connection_maintain (struct CadetConnection *c, int fwd)
+void
+GCC_destroy_without_tunnel (struct CadetConnection *cc)
{
- if (GNUNET_NO != c->destroy)
+ cc->ct = NULL;
+ if ( (CADET_CONNECTION_SENDING_CREATE != cc->state) &&
+ (NULL != cc->mq_man) )
{
- LOG (GNUNET_ERROR_TYPE_INFO, "not sending keepalive, being destroyed\n");
- return;
- }
-
- if (NULL == c->t)
- {
- GNUNET_break (0);
- GCC_debug (c, GNUNET_ERROR_TYPE_ERROR);
- return;
- }
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_CADET_ConnectionDestroyMessage *destroy_msg;
- if (CADET_TUNNEL_SEARCHING == GCT_get_cstate (c->t))
- {
- /* If status is SEARCHING, why is there a connection? Should be WAITING */
- GNUNET_break (0);
- GCT_debug (c->t, GNUNET_ERROR_TYPE_ERROR);
- LOG (GNUNET_ERROR_TYPE_INFO, "not sending keepalive, tunnel SEARCHING\n");
- schedule_next_keepalive (c, fwd);
- 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;
+ /* Need to notify next hop that we are down. */
+ env = GNUNET_MQ_msg (destroy_msg,
+ GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);
+ destroy_msg->cid = cc->cid;
+ GCP_request_mq_cancel (cc->mq_man,
+ env);
+ cc->mq_man = NULL;
}
+ GCC_destroy (cc);
}
/**
- * Keep the connection alive.
+ * Return the tunnel associated with this connection.
*
- * @param c Connection to keep alive.
- * @param fwd Direction.
+ * @param cc connection to query
+ * @return corresponding entry in the tunnel's connection list
*/
-static void
-connection_keepalive (struct CadetConnection *c,
- int fwd)
+struct CadetTConnection *
+GCC_get_ct (struct CadetConnection *cc)
{
- GCC_check_connections ();
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "%s keepalive for %s\n",
- GC_f2s (fwd), GCC_2s (c));
-
- if (fwd)
- c->fwd_maintenance_task = NULL;
- else
- c->bck_maintenance_task = NULL;
- connection_maintain (c, fwd);
- GCC_check_connections ();
- /* Next execution will be scheduled by message_sent or _maintain*/
+ return cc->ct;
}
/**
- * Keep the connection alive in the FWD direction.
+ * Obtain performance @a metrics from @a cc.
*
- * @param cls Closure (connection to keepalive).
+ * @param cc connection to query
+ * @return the metrics
*/
-static void
-connection_fwd_keepalive (void *cls)
+const struct CadetConnectionMetrics *
+GCC_get_metrics (struct CadetConnection *cc)
{
- struct CadetConnection *c = cls;
-
- GCC_check_connections ();
- connection_keepalive (c,
- GNUNET_YES);
- GCC_check_connections ();
+ return &cc->metrics;
}
/**
- * Keep the connection alive in the BCK direction.
+ * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the
+ * tunnel to prevent it from timing out.
*
- * @param cls Closure (connection to keepalive).
+ * @param cls the `struct CadetConnection` to keep alive.
*/
static void
-connection_bck_keepalive (void *cls)
-{
- struct CadetConnection *c = cls;
-
- GCC_check_connections ();
- connection_keepalive (c,
- GNUNET_NO);
- GCC_check_connections ();
-}
+send_keepalive (void *cls);
/**
- * Schedule next keepalive task, taking in consideration
- * the connection state and number of retries.
+ * Keepalive was transmitted. Remember this, and possibly
+ * schedule the next one.
*
- * 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.
+ * @param cls the `struct CadetConnection` to keep alive.
+ * @param cid identifier of the connection within the tunnel, NULL
+ * if transmission failed
*/
static void
-schedule_next_keepalive (struct CadetConnection *c, int fwd)
+keepalive_done (void *cls,
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
{
- struct GNUNET_TIME_Relative delay;
- struct GNUNET_SCHEDULER_Task * *task_id;
- GNUNET_SCHEDULER_TaskCallback keepalive_task;
-
- GCC_check_connections ();
- if (GNUNET_NO == GCC_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_saturating_multiply (create_connection_time,
- c->create_retry);
- if (c->create_retry < 64) // TODO make configurable
- 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;
- }
+ struct CadetConnection *cc = cls;
- /* Check that no one scheduled it before us */
- if (NULL != *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_INFO,
- "next keepalive for %s in in %s\n",
- GCC_2s (c), GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
- GCC_check_connections ();
+ cc->keepalive_qe = NULL;
+ if ( (GNUNET_YES == cc->mqm_ready) &&
+ (NULL == cc->task) )
+ cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
+ &send_keepalive,
+ cc);
}
/**
- * Cancel all transmissions that belong to a certain connection.
+ * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the
+ * tunnel to prevent it from timing out.
*
- * 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?
+ * @param cls the `struct CadetConnection` to keep alive.
*/
static void
-connection_cancel_queues (struct CadetConnection *c,
- int fwd)
+send_keepalive (void *cls)
{
- struct CadetFlowControl *fc;
+ struct CadetConnection *cc = cls;
+ struct GNUNET_MessageHeader msg;
- GCC_check_connections ();
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Cancel %s queues for connection %s\n",
- GC_f2s (fwd), GCC_2s (c));
- if (NULL == c)
+ cc->task = NULL;
+ if (CADET_TUNNEL_KEY_OK != GCT_get_estate (cc->ct->t))
{
- GNUNET_break (0);
+ /* Tunnel not yet ready, wait with keepalives... */
+ cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
+ &send_keepalive,
+ cc);
return;
}
-
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
- if (NULL != fc->poll_task)
- {
- GNUNET_SCHEDULER_cancel (fc->poll_task);
- fc->poll_task = NULL;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " cancelled POLL task for fc %p\n", fc);
- }
- if (NULL != fc->poll_msg)
- {
- GCC_cancel (fc->poll_msg);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " cancelled POLL msg for fc %p\n", fc);
- }
-
- while (NULL != fc->q_head)
- {
- GCC_cancel (fc->q_head);
- }
- GCC_check_connections ();
-}
-
-
-/**
- * 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).
- */
-static void
-send_poll (void *cls)
-{
- static struct CadetEncryptedMessageIdentifier zero;
- struct CadetFlowControl *fc = cls;
- struct GNUNET_CADET_ConnectionHopByHopPollMessage msg;
- struct CadetConnection *c;
- int fwd;
-
- fc->poll_task = NULL;
- GCC_check_connections ();
- c = fc->c;
- fwd = fc == &c->fwd_fc;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Polling connection %s %s\n",
- GCC_2s (c), GC_f2s (fwd));
-
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL);
- msg.header.size = htons (sizeof (msg));
- msg.cid = c->id;
- msg.cemi = fc->last_pid_sent;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " last pid sent: %u\n", ntohl (fc->last_pid_sent.pid));
- fc->poll_msg
- = GCC_send_prebuilt_message (&msg.header,
- UINT16_MAX,
- zero,
- c,
- fc == &c->fwd_fc,
- GNUNET_YES,
- NULL,
- NULL);
- GNUNET_assert (NULL != fc->poll_msg);
- GCC_check_connections ();
-}
-
-
-/**
- * Generic connection timeout implementation.
- *
- * Timeout function due to lack of keepalive/traffic from an endpoint.
- * Destroys connection if called.
- *
- * @param c Connection to destroy.
- * @param fwd Was the timeout from the origin? (FWD timeout)
- */
-static void
-connection_timeout (struct CadetConnection *c, int fwd)
-{
- GCC_check_connections ();
-
+ GNUNET_assert (NULL != cc->ct);
+ GNUNET_assert (GNUNET_YES == cc->mqm_ready);
+ GNUNET_assert (NULL == cc->keepalive_qe);
LOG (GNUNET_ERROR_TYPE_INFO,
- "Connection %s %s timed out. Destroying.\n",
- GCC_2s (c),
- GC_f2s (fwd));
- GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG);
-
- if (GCC_is_origin (c, fwd)) /* Loopback? Something is wrong! */
- {
- GNUNET_break (0);
- return;
- }
-
- /* If dest, send "broken" notification. */
- if (GCC_is_terminal (c, fwd))
- {
- struct CadetPeer *next_hop;
-
- next_hop = fwd ? get_prev_hop (c) : get_next_hop (c);
- send_broken_unknown (&c->id, &my_full_id, NULL, next_hop);
- }
-
- GCC_destroy (c);
- GCC_check_connections ();
-}
-
-
-/**
- * Timeout function due to lack of keepalive/traffic from the owner.
- * Destroys connection if called.
- *
- * @param cls Closure (connection to destroy).
- */
-static void
-connection_fwd_timeout (void *cls)
-{
- struct CadetConnection *c = cls;
-
- c->fwd_maintenance_task = NULL;
- GCC_check_connections ();
- connection_timeout (c, GNUNET_YES);
- GCC_check_connections ();
-}
-
-
-/**
- * Timeout function due to lack of keepalive/traffic from the destination.
- * Destroys connection if called.
- *
- * @param cls Closure (connection to destroy).
- */
-static void
-connection_bck_timeout (void *cls)
-{
- struct CadetConnection *c = cls;
+ "Sending KEEPALIVE on behalf of %s via %s\n",
+ GCC_2s (cc),
+ GCT_2s (cc->ct->t));
+ GNUNET_STATISTICS_update (stats,
+ "# keepalives sent",
+ 1,
+ GNUNET_NO);
+ msg.size = htons (sizeof (msg));
+ msg.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE);
- c->bck_maintenance_task = NULL;
- GCC_check_connections ();
- connection_timeout (c, GNUNET_NO);
- GCC_check_connections ();
+ cc->keepalive_qe
+ = GCT_send (cc->ct->t,
+ &msg,
+ &keepalive_done,
+ cc);
}
/**
- * 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?
+ * We sent a message for which we expect to receive an ACK via
+ * the connection identified by @a cti.
*
- * TODO use heap to improve efficiency of scheduler.
+ * @param cid connection identifier where we expect an ACK
*/
-static void
-connection_reset_timeout (struct CadetConnection *c, int fwd)
+void
+GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s reset timeout\n", GC_f2s (fwd));
- if (GCC_is_origin (c, fwd)) /* Startpoint */
- {
- schedule_next_keepalive (c, fwd);
- if (NULL != c->maintenance_q)
- {
- GCP_send_cancel (c->maintenance_q);
- c->maintenance_q = NULL; /* Is set to NULL by conn_message_sent anyway */
- }
- }
- else /* Relay, endpoint. */
- {
- struct GNUNET_TIME_Relative delay;
- struct GNUNET_SCHEDULER_Task * *ti;
- GNUNET_SCHEDULER_TaskCallback f;
-
- ti = fwd ? &c->fwd_maintenance_task : &c->bck_maintenance_task;
+ struct CadetConnection *cc;
- if (NULL != *ti)
- GNUNET_SCHEDULER_cancel (*ti);
- delay = GNUNET_TIME_relative_saturating_multiply (refresh_connection_time, 4);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " timing out in %s\n",
- GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_NO));
- f = fwd ? &connection_fwd_timeout : &connection_bck_timeout;
- *ti = GNUNET_SCHEDULER_add_delayed (delay, f, c);
- }
+ cc = GCC_lookup (cid);
+ if (NULL == cc)
+ return; /* whopise, connection alredy down? */
+ cc->metrics.num_acked_transmissions++;
}
/**
- * Iterator to compare each connection's path with the path of a new connection.
+ * We observed an ACK for a message that was originally sent via
+ * the connection identified by @a cti.
*
- * If the connection coincides, the c member of path is set to the connection
- * and the destroy flag of the connection is set.
- *
- * @param cls Closure (new path).
- * @param c Connection in the tunnel to check.
+ * @param cti connection identifier where we got an ACK for a message
+ * that was originally sent via this connection (the ACK
+ * may have gotten back to us via a different connection).
*/
-static void
-check_path (void *cls, struct CadetConnection *c)
+void
+GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
{
- struct CadetConnection *new_conn = cls;
- struct CadetPeerPath *path = new_conn->path;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " checking %s (%p), length %u\n",
- GCC_2s (c), c, c->path->length);
+ struct CadetConnection *cc;
- if (c != new_conn
- && GNUNET_NO == c->destroy
- && CADET_CONNECTION_BROKEN != c->state
- && CADET_CONNECTION_DESTROYED != c->state
- && path_equivalent (path, c->path))
- {
- new_conn->destroy = GNUNET_YES; /* Do not mark_destroyed, */
- new_conn->path->c = c; /* this is only a flag for the Iterator. */
- LOG (GNUNET_ERROR_TYPE_DEBUG, " MATCH!\n");
- }
+ cc = GCC_lookup (cid);
+ if (NULL == cc)
+ return; /* whopise, connection alredy down? */
+ cc->metrics.num_successes++;
}
/**
- * Finds out if this path is already being used by an existing connection.
- *
- * Checks the tunnel towards the destination to see if it contains
- * any connection with the same path.
+ * We observed some the given @a latency on the connection
+ * identified by @a cti. (The same connection was taken
+ * in both directions.)
*
- * If the existing connection is ready, it is kept.
- * Otherwise if the sender has a smaller ID that ours, we accept it (and
- * the peer will eventually reject our attempt).
- *
- * @param path Path to check.
- * @return #GNUNET_YES if the tunnel has a connection with the same path,
- * #GNUNET_NO otherwise.
+ * @param cid connection identifier where we measured latency
+ * @param latency the observed latency
*/
-static int
-does_connection_exist (struct CadetConnection *conn)
+void
+GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+ struct GNUNET_TIME_Relative latency)
{
- struct CadetPeer *p;
- struct CadetTunnel *t;
- struct CadetConnection *c;
-
- p = GCP_get_short (conn->path->peers[0], GNUNET_NO);
- if (NULL == p)
- return GNUNET_NO;
- t = GCP_get_tunnel (p);
- if (NULL == t)
- return GNUNET_NO;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking for duplicates\n");
+ struct CadetConnection *cc;
+ double weight;
+ double result;
- GCT_iterate_connections (t, &check_path, conn);
-
- if (GNUNET_YES == conn->destroy)
- {
- c = conn->path->c;
- conn->destroy = GNUNET_NO;
- conn->path->c = conn;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " found duplicate of %s\n", GCC_2s (conn));
- LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate: %s\n", GCC_2s (c));
- GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG);
- if (CADET_CONNECTION_READY == c->state)
- {
- /* The other peer confirmed a live connection with this path,
- * why are they trying to duplicate it? */
- GNUNET_STATISTICS_update (stats, "# duplicate connections", 1, GNUNET_NO);
- return GNUNET_YES;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate not ready, connection unique\n");
- return GNUNET_NO;
- }
+ cc = GCC_lookup (cid);
+ if (NULL == cc)
+ return; /* whopise, connection alredy down? */
+ GNUNET_STATISTICS_update (stats,
+ "# latencies observed",
+ 1,
+ GNUNET_NO);
+ cc->latency_datapoints++;
+ if (cc->latency_datapoints >= 7)
+ weight = 7.0;
else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " %s has no duplicates\n", GCC_2s (conn));
- return GNUNET_NO;
- }
+ weight = cc->latency_datapoints;
+ /* Compute weighted average, giving at MOST weight 7 to the
+ existing values, or less if that value is based on fewer than 7
+ measurements. */
+ result = (weight * cc->metrics.aged_latency.rel_value_us) + 1.0 * latency.rel_value_us;
+ result /= (weight + 1.0);
+ cc->metrics.aged_latency.rel_value_us = (uint64_t) result;
}
/**
- * @brief Check if the tunnel this connection belongs to has any other
- * connection with the same path, and destroy one if so.
+ * A #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK was received for this connection, implying
+ * that the end-to-end connection is up. Process it.
*
- * @param cls Closure (connection to check).
- */
-static void
-check_duplicates (void *cls)
-{
- struct CadetConnection *c = cls;
-
- c->check_duplicates_task = NULL;
- if (GNUNET_YES == does_connection_exist (c))
- {
- GCT_debug (c->t, GNUNET_ERROR_TYPE_DEBUG);
- send_broken (c, &my_full_id, &my_full_id, GCC_is_origin (c, GNUNET_YES));
- GCC_destroy (c);
- }
-}
-
-
-/**
- * Wait for enough time to let any dead connections time out and check for
- * any remaining duplicates.
- *
- * @param c Connection that is a potential duplicate.
- */
-static void
-schedule_check_duplicates (struct CadetConnection *c)
-{
- struct GNUNET_TIME_Relative delay;
-
- if (NULL != c->check_duplicates_task)
- return;
- delay = GNUNET_TIME_relative_saturating_multiply (refresh_connection_time, 5);
- c->check_duplicates_task = GNUNET_SCHEDULER_add_delayed (delay,
- &check_duplicates,
- 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)
-{
- c->next_peer = get_next_hop (c);
- c->prev_peer = get_prev_hop (c);
- GNUNET_assert (c->next_peer != c->prev_peer);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "register neighbors for connection %s\n",
- GCC_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",
- GCC_2s (c),
- c->next_peer);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "next peer %p %s\n",
- c->next_peer,
- GCP_2s (c->next_peer));
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "putting connection %s to prev peer %p\n",
- GCC_2s (c),
- c->prev_peer);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "prev peer %p %s\n",
- c->prev_peer,
- GCP_2s (c->prev_peer));
-
- if ( (GNUNET_NO == GCP_is_neighbor (c->next_peer)) ||
- (GNUNET_NO == GCP_is_neighbor (c->prev_peer)) )
- {
- if (GCC_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",
- GCP_2s (c->prev_peer),
- GCP_is_neighbor (c->prev_peer));
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " next: %s, neighbor?: %d\n",
- GCP_2s (c->next_peer),
- GCP_is_neighbor (c->next_peer));
- return GNUNET_SYSERR;
- }
- GCP_add_connection (c->next_peer, c, GNUNET_NO);
- GCP_add_connection (c->prev_peer, c, GNUNET_YES);
-
- 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; FIXME dont use next_peer, prev_peer
- /* Either already unregistered or never got registered, it's ok either way. */
- if (NULL == c->path)
- return;
- if (NULL != c->next_peer)
- {
- GCP_remove_connection (c->next_peer, c);
- c->next_peer = NULL;
- }
- if (NULL != c->prev_peer)
- {
- GCP_remove_connection (c->prev_peer, c);
- c->prev_peer = NULL;
- }
-}
-
-
-/**
- * Invalidates all paths towards all peers that comprise the connection which
- * rely on the disconnected peer.
- *
- * ~O(n^3) (peers in connection * paths/peer * links/path)
- *
- * @param c Connection whose peers' paths to clean.
- * @param disconnected Peer that disconnected.
- */
-static void
-invalidate_paths (struct CadetConnection *c,
- struct CadetPeer *disconnected)
-{
- struct CadetPeer *peer;
- unsigned int i;
-
- for (i = 0; i < c->path->length; i++)
- {
- peer = GCP_get_short (c->path->peers[i], GNUNET_NO);
- if (NULL != peer)
- GCP_notify_broken_link (peer, &my_full_id, GCP_get_id (disconnected));
- }
-}
-
-
-/**
- * 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)
-{
- GCP_add_tunnel (peer);
- c->t = GCP_get_tunnel (peer);
- GCT_add_connection (c->t, c);
-}
-
-
-/**
- * Log receipt of message on stderr (INFO level).
- *
- * @param message Message received.
- * @param peer Peer who sent the message.
- * @param conn_id Connection ID of the message.
- */
-static void
-log_message (const struct GNUNET_MessageHeader *message,
- const struct CadetPeer *peer,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *conn_id)
-{
- uint16_t size;
- uint16_t type;
- char *arrow;
-
- size = ntohs (message->size);
- type = ntohs (message->type);
- switch (type)
- {
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
- arrow = "==";
- break;
- default:
- arrow = "--";
- }
- LOG (GNUNET_ERROR_TYPE_INFO,
- "<%s %s on conn %s from %s, %6u bytes\n",
- arrow,
- GC_m2s (type),
- GNUNET_sh2s (&conn_id->connection_of_tunnel),
- GCP_2s(peer),
- (unsigned int) size);
-}
-
-/******************************************************************************/
-/******************************** API ***********************************/
-/******************************************************************************/
-
-/**
- * Handler for connection creation.
- *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param cc the connection that got the ACK.
*/
void
-GCC_handle_create (struct CadetPeer *peer,
- const struct GNUNET_CADET_ConnectionCreateMessage *msg)
+GCC_handle_connection_create_ack (struct CadetConnection *cc)
{
- static struct CadetEncryptedMessageIdentifier zero;
- const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid;
- struct GNUNET_PeerIdentity *id;
- struct CadetPeerPath *path;
- struct CadetPeer *dest_peer;
- struct CadetPeer *orig_peer;
- struct CadetConnection *c;
- unsigned int own_pos;
- uint16_t size;
-
- GCC_check_connections ();
- size = ntohs (msg->header.size);
-
- /* Calculate hops */
- size -= sizeof (struct GNUNET_CADET_ConnectionCreateMessage);
- if (0 != size % sizeof (struct GNUNET_PeerIdentity))
- {
- GNUNET_break_op (0);
- return;
- }
- size /= sizeof (struct GNUNET_PeerIdentity);
- if (1 > size)
- {
- GNUNET_break_op (0);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " path has %u hops.\n", size);
-
- /* Get parameters */
- cid = &msg->cid;
- log_message (&msg->header, 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 = path_build_from_peer_ids ((struct GNUNET_PeerIdentity *) &msg[1],
- size, myid, &own_pos);
- if (NULL == path)
- {
- /* Path was malformed, probably our own ID was not in it. */
- GNUNET_STATISTICS_update (stats, "# malformed paths", 1, GNUNET_NO);
- GNUNET_break_op (0);
- return;
- }
- if (0 == own_pos)
- {
- /* We received this request from a neighbor, we cannot be origin */
- GNUNET_STATISTICS_update (stats, "# fake paths", 1, GNUNET_NO);
- GNUNET_break_op (0);
- path_destroy (path);
- return;
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Own position: %u\n", own_pos);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Creating connection\n");
- c = GCC_new (cid, NULL, path, own_pos);
- if (NULL == c)
- {
- if (path->length - 1 == own_pos)
- {
- /* If we are destination, why did the creation fail? */
- GNUNET_break (0);
- path_destroy (path);
- GCC_check_connections ();
- return;
- }
- send_broken_unknown (cid, &my_full_id,
- GNUNET_PEER_resolve2 (path->peers[own_pos + 1]),
- peer);
- path_destroy (path);
- GCC_check_connections ();
- return;
- }
- GCP_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 = GCP_get (&id[size - 1], GNUNET_YES);
- orig_peer = GCP_get (&id[0], GNUNET_YES);
-
- /* Is it a connection to us? */
- if (c->own_pos == path->length - 1)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " It's for us!\n");
- GCP_add_path_to_origin (orig_peer, path_duplicate (path), GNUNET_YES);
-
- add_to_peer (c, orig_peer);
- if (GNUNET_YES == does_connection_exist (c))
- {
- /* Peer created a connection equal to one we think exists
- * and is fine.
- * Solution: Keep both and postpone disambiguation. In the meantime
- * the connection will time out or peer will inform us it is broken.
- *
- * Other options:
- * - Use explicit duplicate.
- * - Accept new conn and destroy the old. (interruption in higher level)
- * - Keep the one with higher ID / created by peer with higher ID. */
- schedule_check_duplicates (c);
- }
-
- if (CADET_TUNNEL_NEW == GCT_get_cstate (c->t))
- GCT_change_cstate (c->t, CADET_TUNNEL_WAITING);
- if (NULL == c->maintenance_q)
- send_connection_ack (c, GNUNET_NO);
- if (CADET_CONNECTION_SENT == c->state)
- connection_change_state (c, CADET_CONNECTION_ACK);
- }
- else
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received CADET_CONNECTION_CREATE_ACK for %s in state %d (%s)\n",
+ GCC_2s (cc),
+ cc->state,
+ (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy");
+ if (CADET_CONNECTION_READY == cc->state)
+ return; /* Duplicate ACK, ignore */
+ if (NULL != cc->task)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n");
- GCP_add_path (dest_peer, path_duplicate (path), GNUNET_NO);
- GCP_add_path_to_origin (orig_peer, path_duplicate (path), GNUNET_NO);
- (void) GCC_send_prebuilt_message (&msg->header,
- 0,
- zero,
- c,
- GNUNET_YES, GNUNET_YES,
- NULL, NULL);
+ GNUNET_SCHEDULER_cancel (cc->task);
+ cc->task = NULL;
}
- path_destroy (path);
- GCC_check_connections ();
+ cc->metrics.age = GNUNET_TIME_absolute_get ();
+ update_state (cc,
+ CADET_CONNECTION_READY,
+ cc->mqm_ready);
+ if ( (NULL == cc->keepalive_qe) &&
+ (GNUNET_YES == cc->mqm_ready) &&
+ (NULL == cc->task) )
+ cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
+ &send_keepalive,
+ cc);
}
/**
- * Handler for connection confirmations.
+ * Handle KX message.
*
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param cc connection that received encrypted message
+ * @param msg the key exchange message
*/
void
-GCC_handle_confirm (struct CadetPeer *peer,
- const struct GNUNET_CADET_ConnectionCreateAckMessage *msg)
+GCC_handle_kx (struct CadetConnection *cc,
+ const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
{
- static struct CadetEncryptedMessageIdentifier zero;
- struct CadetConnection *c;
- enum CadetConnectionState oldstate;
- int fwd;
-
- GCC_check_connections ();
- log_message (&msg->header, 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);
- GCC_check_connections ();
- return;
- }
- if (GNUNET_NO != c->destroy)
+ if (CADET_CONNECTION_SENT == cc->state)
{
- GNUNET_assert (CADET_CONNECTION_DESTROYED == c->state);
- GNUNET_STATISTICS_update (stats, "# control on dying connection",
- 1, GNUNET_NO);
+ /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine,
+ clearly something is working, so pretend we got an ACK. */
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "connection %s being destroyed, ignoring confirm\n",
- GCC_2s (c));
- GCC_check_connections ();
- return;
- }
-
- oldstate = c->state;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " via peer %s\n", GCP_2s (peer));
- if (get_next_hop (c) == peer)
- {
- 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) == peer)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " FINAL ACK\n");
- fwd = GNUNET_YES;
- connection_change_state (c, CADET_CONNECTION_READY);
- }
- else
- {
- GNUNET_STATISTICS_update (stats, "# control on connection from wrong peer",
- 1, GNUNET_NO);
- GNUNET_break_op (0);
- return;
- }
-
- connection_reset_timeout (c, fwd);
-
- GNUNET_assert (NULL != c->path);
- GCP_add_path_to_all (c->path, GNUNET_YES);
-
- /* Message for us as creator? */
- if (GNUNET_YES == GCC_is_origin (c, GNUNET_YES))
- {
- if (GNUNET_NO != fwd)
- {
- GNUNET_break (0);
- return;
- }
- 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)
- {
- c->create_retry = 1;
- connection_reset_timeout (c, GNUNET_YES);
- }
-
- /* Change connection state, send ACK */
- connection_change_state (c, CADET_CONNECTION_READY);
- send_connection_ack (c, GNUNET_YES);
-
- /* Change tunnel state, trigger KX */
- if (CADET_TUNNEL_WAITING == GCT_get_cstate (c->t))
- GCT_change_cstate (c->t, CADET_TUNNEL_READY);
- GCC_check_connections ();
- return;
- }
-
- /* Message for us as destination? */
- if (GCC_is_terminal (c, GNUNET_YES))
- {
- if (GNUNET_YES != fwd)
- {
- GNUNET_break (0);
- return;
- }
- 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_TUNNEL_WAITING == GCT_get_cstate (c->t))
- GCT_change_cstate (c->t, CADET_TUNNEL_READY);
- GCC_check_connections ();
+ "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n",
+ GCC_2s (cc));
+ GCC_handle_connection_create_ack (cc);
}
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n");
- (void) GCC_send_prebuilt_message (&msg->header, 0,
- zero,
- c,
- fwd,
- GNUNET_YES, NULL, NULL);
- }
- GCC_check_connections ();
+ GCT_handle_kx (cc->ct,
+ msg);
}
/**
- * Handler for notifications of broken connections.
+ * Handle KX_AUTH message.
*
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param cc connection that received encrypted message
+ * @param msg the key exchange message
*/
void
-GCC_handle_broken (struct CadetPeer *peer,
- const struct GNUNET_CADET_ConnectionBrokenMessage *msg)
+GCC_handle_kx_auth (struct CadetConnection *cc,
+ const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg)
{
- static struct CadetEncryptedMessageIdentifier zero;
- struct CadetConnection *c;
- struct CadetTunnel *t;
- int fwd;
-
- GCC_check_connections ();
- log_message (&msg->header, peer, &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");
- GNUNET_STATISTICS_update (stats, "# duplicate CONNECTION_BROKEN",
- 1, GNUNET_NO);
- GCC_check_connections ();
- return;
- }
-
- t = c->t;
-
- fwd = is_fwd (c, peer);
- if (GNUNET_SYSERR == fwd)
- {
- GNUNET_break_op (0);
- GCC_check_connections ();
- return;
- }
- mark_destroyed (c);
- if (GCC_is_terminal (c, fwd))
- {
- struct CadetPeer *endpoint;
-
- if (NULL == t)
- {
- /* A terminal connection should not have 't' set to NULL. */
- GNUNET_break (0);
- GCC_debug (c, GNUNET_ERROR_TYPE_ERROR);
- return;
- }
- endpoint = GCP_get_short (c->path->peers[c->path->length - 1], GNUNET_YES);
- if (2 < c->path->length)
- path_invalidate (c->path);
- GCP_notify_broken_link (endpoint, &msg->peer1, &msg->peer2);
-
- connection_change_state (c, CADET_CONNECTION_BROKEN);
- GCT_remove_connection (t, c);
- c->t = NULL;
-
- GCC_destroy (c);
- }
- else
+ if (CADET_CONNECTION_SENT == cc->state)
{
- (void) GCC_send_prebuilt_message (&msg->header, 0,
- zero, c, fwd,
- GNUNET_YES, NULL, NULL);
- connection_cancel_queues (c, !fwd);
+ /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine,
+ clearly something is working, so pretend we got an ACK. */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n",
+ GCC_2s (cc));
+ GCC_handle_connection_create_ack (cc);
}
- GCC_check_connections ();
- return;
+ GCT_handle_kx_auth (cc->ct,
+ msg);
}
/**
- * Handler for notifications of destroyed connections.
+ * Handle encrypted message.
*
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param cc connection that received encrypted message
+ * @param msg the encrypted message to decrypt
*/
void
-GCC_handle_destroy (struct CadetPeer *peer,
- const struct GNUNET_CADET_ConnectionDestroyMessage *msg)
+GCC_handle_encrypted (struct CadetConnection *cc,
+ const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
{
- static struct CadetEncryptedMessageIdentifier zero;
- struct CadetConnection *c;
- int fwd;
-
- GCC_check_connections ();
- log_message (&msg->header, peer, &msg->cid);
- c = connection_get (&msg->cid);
- if (NULL == c)
+ if (CADET_CONNECTION_SENT == cc->state)
{
- /* 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);
+ /* We didn't get the CREATE_ACK, but instead got payload. That's fine,
+ clearly something is working, so pretend we got an ACK. */
LOG (GNUNET_ERROR_TYPE_DEBUG,
- " connection unknown destroyed: previously destroyed?\n");
- GCC_check_connections ();
- return;
- }
-
- fwd = is_fwd (c, peer);
- if (GNUNET_SYSERR == fwd)
- {
- GNUNET_break_op (0);
- GCC_check_connections ();
- return;
- }
-
- if (GNUNET_NO == GCC_is_terminal (c, fwd))
- {
- (void) GCC_send_prebuilt_message (&msg->header, 0,
- zero, c, fwd,
- GNUNET_YES, NULL, NULL);
+ "Faking connection ACK for %s due to ENCRYPTED payload\n",
+ GCC_2s (cc));
+ GCC_handle_connection_create_ack (cc);
}
- else if (0 == c->pending_messages)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " directly destroying connection!\n");
- GCC_destroy (c);
- GCC_check_connections ();
- return;
- }
- mark_destroyed (c);
- if (NULL != c->t)
- {
- GCT_remove_connection (c->t, c);
- c->t = NULL;
- }
- GCC_check_connections ();
- return;
+ cc->metrics.last_use = GNUNET_TIME_absolute_get ();
+ GCT_handle_encrypted (cc->ct,
+ msg);
}
/**
- * Handler for cadet network traffic hop-by-hop acks.
+ * Send a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE message to the
+ * first hop.
*
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param cls the `struct CadetConnection` to initiate
*/
-void
-GCC_handle_ack (struct CadetPeer *peer,
- const struct GNUNET_CADET_ConnectionEncryptedAckMessage *msg)
-{
- struct CadetConnection *c;
- struct CadetFlowControl *fc;
- struct CadetEncryptedMessageIdentifier ack;
- int fwd;
-
- GCC_check_connections ();
- log_message (&msg->header, 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);
- GCC_check_connections ();
- return;
- }
-
- /* Is this a forward or backward ACK? */
- if (get_next_hop (c) == peer)
- {
- fc = &c->fwd_fc;
- fwd = GNUNET_YES;
- }
- else if (get_prev_hop (c) == peer)
- {
- fc = &c->bck_fc;
- fwd = GNUNET_NO;
- }
- else
- {
- GNUNET_break_op (0);
- return;
- }
-
- ack = msg->cemi_max;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " %s ACK %u (was %u)\n",
- GC_f2s (fwd),
- ntohl (ack.pid),
- ntohl (fc->last_ack_recv.pid));
- if (GC_is_pid_bigger (ntohl (ack.pid),
- ntohl (fc->last_ack_recv.pid)))
- fc->last_ack_recv = ack;
-
- /* Cancel polling if the ACK is big enough. */
- if ( (NULL != fc->poll_task) &
- GC_is_pid_bigger (ntohl (fc->last_ack_recv.pid),
- ntohl (fc->last_pid_sent.pid)))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Cancel poll\n");
- GNUNET_SCHEDULER_cancel (fc->poll_task);
- fc->poll_task = NULL;
- fc->poll_time = GNUNET_TIME_UNIT_SECONDS;
- }
-
- GCC_check_connections ();
+static void
+send_create (void *cls)
+{
+ struct CadetConnection *cc = cls;
+ struct GNUNET_CADET_ConnectionCreateMessage *create_msg;
+ struct GNUNET_PeerIdentity *pids;
+ struct GNUNET_MQ_Envelope *env;
+ unsigned int path_length;
+
+ cc->task = NULL;
+ GNUNET_assert (GNUNET_YES == cc->mqm_ready);
+ path_length = GCPP_get_length (cc->path);
+ env = GNUNET_MQ_msg_extra (create_msg,
+ (1 + path_length) * sizeof (struct GNUNET_PeerIdentity),
+ GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE);
+ create_msg->options = htonl ((uint32_t) cc->options);
+ create_msg->cid = cc->cid;
+ pids = (struct GNUNET_PeerIdentity *) &create_msg[1];
+ pids[0] = my_full_id;
+ for (unsigned int i=0;i<path_length;i++)
+ pids[i + 1] = *GCP_get_id (GCPP_get_peer_at_offset (cc->path,
+ i));
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending CADET_CONNECTION_CREATE message for %s\n",
+ GCC_2s (cc));
+ cc->env = env;
+ update_state (cc,
+ CADET_CONNECTION_SENT,
+ GNUNET_NO);
+ GCP_send (cc->mq_man,
+ env);
}
/**
- * Handler for cadet network traffic hop-by-hop data counter polls.
+ * Send a CREATE_ACK message towards the origin.
*
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param cls the `struct CadetConnection` to initiate
*/
-void
-GCC_handle_poll (struct CadetPeer *peer,
- const struct GNUNET_CADET_ConnectionHopByHopPollMessage *msg)
+static void
+send_create_ack (void *cls)
{
- struct CadetConnection *c;
- struct CadetFlowControl *fc;
- struct CadetEncryptedMessageIdentifier pid;
- int fwd;
-
- GCC_check_connections ();
- log_message (&msg->header, 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_sh2s (&msg->cid.connection_of_tunnel));
- send_broken_unknown (&msg->cid,
- &my_full_id,
- NULL,
- peer);
- GCC_check_connections ();
- return;
- }
-
- /* 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.
- */
- if (get_next_hop (c) == peer)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD FC\n");
- fc = &c->fwd_fc;
- }
- else if (get_prev_hop (c) == peer)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK FC\n");
- fc = &c->bck_fc;
- }
- else
- {
- GNUNET_break_op (0);
- return;
- }
+ struct CadetConnection *cc = cls;
+ struct GNUNET_CADET_ConnectionCreateAckMessage *ack_msg;
+ struct GNUNET_MQ_Envelope *env;
- pid = msg->cemi;
+ cc->task = NULL;
+ GNUNET_assert (CADET_CONNECTION_CREATE_RECEIVED == cc->state);
LOG (GNUNET_ERROR_TYPE_DEBUG,
- " PID %u, OLD %u\n",
- ntohl (pid.pid),
- ntohl (fc->last_pid_recv.pid));
- fc->last_pid_recv = pid;
- fwd = fc == &c->bck_fc;
- GCC_send_ack (c, fwd, GNUNET_YES);
- GCC_check_connections ();
+ "Sending CONNECTION_CREATE_ACK message for %s\n",
+ GCC_2s (cc));
+ GNUNET_assert (GNUNET_YES == cc->mqm_ready);
+ env = GNUNET_MQ_msg (ack_msg,
+ GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK);
+ ack_msg->cid = cc->cid;
+ cc->env = env;
+ update_state (cc,
+ CADET_CONNECTION_READY,
+ GNUNET_NO);
+ GCP_send (cc->mq_man,
+ env);
}
/**
- * Check the message against internal state and test if it goes FWD or BCK.
- *
- * Updates the PID, state and timeout values for the connection.
- *
- * @param message Message to check. It must belong to an existing connection.
- * @param cid Connection ID (even if @a c is NULL, the ID is still needed).
- * @param c Connection this message should belong. If NULL, check fails.
- * @param sender Neighbor that sent the message.
+ * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a
+ * connection that we already have. Either our ACK got lost
+ * or something is fishy. Consider retransmitting the ACK.
*
- * @return #GNUNET_YES if the message goes FWD.
- * #GNUNET_NO if it goes BCK.
- * #GNUNET_SYSERR if there is an error (unauthorized sender, ...).
+ * @param cc connection that got the duplicate CREATE
*/
-static int
-check_message (const struct GNUNET_MessageHeader *message,
- const struct GNUNET_CADET_ConnectionTunnelIdentifier* cid,
- struct CadetConnection *c,
- struct CadetPeer *sender,
- struct CadetEncryptedMessageIdentifier pid)
+void
+GCC_handle_duplicate_create (struct CadetConnection *cc)
{
- struct CadetFlowControl *fc;
- struct CadetPeer *hop;
- int fwd;
- uint16_t type;
-
- /* Check connection */
- if (NULL == c)
+ if (GNUNET_YES == cc->mqm_ready)
{
- GNUNET_STATISTICS_update (stats,
- "# unknown connection",
- 1, GNUNET_NO);
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "%s on unknown connection %s\n",
- GC_m2s (ntohs (message->type)),
- GNUNET_sh2s (&cid->connection_of_tunnel));
- GNUNET_break_op (0);
- send_broken_unknown (cid,
- &my_full_id,
- NULL,
- sender);
- return GNUNET_SYSERR;
- }
-
- /* Check if origin is as expected */
- hop = get_prev_hop (c);
- if (sender == hop)
- {
- fwd = GNUNET_YES;
+ "Got duplicate CREATE for %s, scheduling another ACK (%s)\n",
+ GCC_2s (cc),
+ (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy");
+ /* Revert back to the state of having only received the 'CREATE',
+ and immediately proceed to send the CREATE_ACK. */
+ update_state (cc,
+ CADET_CONNECTION_CREATE_RECEIVED,
+ cc->mqm_ready);
+ if (NULL != cc->task)
+ GNUNET_SCHEDULER_cancel (cc->task);
+ cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack,
+ cc);
}
else
{
- hop = get_next_hop (c);
- GNUNET_break (hop == c->next_peer);
- if (sender == hop)
- {
- fwd = GNUNET_NO;
- }
- else
- {
- /* Unexpected peer sending traffic on a connection. */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- }
-
- /* Check PID for payload messages */
- type = ntohs (message->type);
- if (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED == type)
- {
- fc = fwd ? &c->bck_fc : &c->fwd_fc;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " PID %u (expected in interval [%u,%u])\n",
- ntohl (pid.pid),
- ntohl (fc->last_pid_recv.pid) + 1,
- ntohl (fc->last_ack_sent.pid));
- if (GC_is_pid_bigger (ntohl (pid.pid),
- ntohl (fc->last_ack_sent.pid)))
- {
- GNUNET_STATISTICS_update (stats,
- "# unsolicited message",
- 1,
- GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "Received PID %u, (prev %u), ACK %u\n",
- pid, fc->last_pid_recv, fc->last_ack_sent);
- return GNUNET_SYSERR;
- }
- if (GC_is_pid_bigger (ntohl (pid.pid),
- ntohl (fc->last_pid_recv.pid)))
- {
- unsigned int delta;
-
- delta = ntohl (pid.pid) - ntohl (fc->last_pid_recv.pid);
- fc->last_pid_recv = pid;
- fc->recv_bitmap <<= delta;
- fc->recv_bitmap |= 1;
- }
- else
- {
- GNUNET_STATISTICS_update (stats,
- "# out of order PID",
- 1,
- GNUNET_NO);
- if (GNUNET_NO == is_ooo_ok (fc->last_pid_recv,
- pid,
- fc->recv_bitmap))
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "PID %u unexpected (%u+), dropping!\n",
- ntohl (pid.pid),
- ntohl (fc->last_pid_recv.pid) - 31);
- return GNUNET_SYSERR;
- }
- fc->recv_bitmap |= get_recv_bitmask (fc->last_pid_recv,
- pid);
- }
- }
-
- /* 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_TUNNEL_WAITING == GCT_get_cstate (c->t))
- GCT_change_cstate (c->t, CADET_TUNNEL_READY);
- }
+ /* We are currently sending something else back, which
+ can only be an ACK or payload, either of which would
+ do. So actually no need to do anything. */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Got duplicate CREATE for %s. MQ is busy, not queueing another ACK\n",
+ GCC_2s (cc));
}
- connection_reset_timeout (c, fwd);
-
- return fwd;
}
/**
- * Handler for key exchange traffic (Axolotl KX).
+ * There has been a change in the message queue existence for our
+ * peer at the first hop. Adjust accordingly.
*
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param cls the `struct CadetConnection`
+ * @param available #GNUNET_YES if sending is now possible,
+ * #GNUNET_NO if sending is no longer possible
+ * #GNUNET_SYSERR if sending is no longer possible
+ * and the last envelope was discarded
*/
-void
-GCC_handle_kx (struct CadetPeer *peer,
- const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
+static void
+manage_first_hop_mq (void *cls,
+ int available)
{
- static struct CadetEncryptedMessageIdentifier zero;
- const struct GNUNET_CADET_ConnectionTunnelIdentifier* cid;
- struct CadetConnection *c;
- int fwd;
-
- GCC_check_connections ();
- cid = &msg->cid;
- log_message (&msg->header, peer, cid);
-
- c = connection_get (cid);
- fwd = check_message (&msg->header,
- cid,
- c,
- peer,
- zero);
-
- /* If something went wrong, discard message. */
- if (GNUNET_SYSERR == fwd)
- {
- GNUNET_break_op (0);
- GCC_check_connections ();
- return;
- }
+ struct CadetConnection *cc = cls;
- /* Is this message for us? */
- if (GCC_is_terminal (c, fwd))
+ if (GNUNET_YES != available)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " message for us!\n");
- GNUNET_STATISTICS_update (stats, "# received KX", 1, GNUNET_NO);
- if (NULL == c->t)
+ /* Connection is down, for now... */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Core MQ for %s went down\n",
+ GCC_2s (cc));
+ update_state (cc,
+ CADET_CONNECTION_NEW,
+ GNUNET_NO);
+ cc->retry_delay = GNUNET_TIME_UNIT_ZERO;
+ if (NULL != cc->task)
{
- GNUNET_break (0);
- return;
+ GNUNET_SCHEDULER_cancel (cc->task);
+ cc->task = NULL;
}
- GCT_handle_kx (c->t, msg);
- GCC_check_connections ();
- return;
- }
-
- /* 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);
- (void) GCC_send_prebuilt_message (&msg->header, 0,
- zero, c, fwd,
- GNUNET_NO, NULL, NULL);
- GCC_check_connections ();
-}
-
-
-/**
- * Handler for encrypted cadet network traffic (channel mgmt, data).
- *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
- */
-void
-GCC_handle_encrypted (struct CadetPeer *peer,
- const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
-{
- static struct CadetEncryptedMessageIdentifier zero;
- const struct GNUNET_CADET_ConnectionTunnelIdentifier* cid;
- struct CadetConnection *c;
- struct CadetEncryptedMessageIdentifier pid;
- int fwd;
-
- GCC_check_connections ();
- cid = &msg->cid;
- pid = msg->cemi;
- log_message (&msg->header, peer, cid);
-
- c = connection_get (cid);
- fwd = check_message (&msg->header,
- cid,
- c,
- peer,
- pid);
-
- /* If something went wrong, discard message. */
- if (GNUNET_SYSERR == fwd)
- {
- GCC_check_connections ();
return;
}
- /* Is this message for us? */
- if (GCC_is_terminal (c, fwd))
- {
- GNUNET_STATISTICS_update (stats, "# received encrypted", 1, GNUNET_NO);
-
- if (NULL == c->t)
+ update_state (cc,
+ cc->state,
+ GNUNET_YES);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Core MQ for %s became available in state %d\n",
+ GCC_2s (cc),
+ cc->state);
+ switch (cc->state)
+ {
+ case CADET_CONNECTION_NEW:
+ /* Transmit immediately */
+ cc->task = GNUNET_SCHEDULER_add_now (&send_create,
+ cc);
+ break;
+ case CADET_CONNECTION_SENDING_CREATE:
+ /* Should not be possible to be called in this state. */
+ GNUNET_assert (0);
+ break;
+ case CADET_CONNECTION_SENT:
+ /* Retry a bit later... */
+ cc->retry_delay = GNUNET_TIME_STD_BACKOFF (cc->retry_delay);
+ cc->task = GNUNET_SCHEDULER_add_delayed (cc->retry_delay,
+ &send_create,
+ cc);
+ break;
+ case CADET_CONNECTION_CREATE_RECEIVED:
+ /* We got the 'CREATE' (incoming connection), should send the CREATE_ACK */
+ cc->metrics.age = GNUNET_TIME_absolute_get ();
+ cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack,
+ cc);
+ break;
+ case CADET_CONNECTION_READY:
+ if ( (NULL == cc->keepalive_qe) &&
+ (GNUNET_YES == cc->mqm_ready) &&
+ (NULL == cc->task) )
{
- GNUNET_break (GNUNET_NO != c->destroy);
- return;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Scheduling keepalive for %s in %s\n",
+ GCC_2s (cc),
+ GNUNET_STRINGS_relative_time_to_string (keepalive_period,
+ GNUNET_YES));
+ cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
+ &send_keepalive,
+ cc);
}
- GCT_handle_encrypted (c->t, msg);
- GCC_send_ack (c, fwd, GNUNET_NO);
- GCC_check_connections ();
- return;
+ break;
}
-
- /* 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);
- (void) GCC_send_prebuilt_message (&msg->header, 0,
- zero, c, fwd,
- GNUNET_NO, NULL, NULL);
- GCC_check_connections ();
}
/**
- * Initialize the connections subsystem
+ * Create a connection to @a destination via @a path and notify @a cb
+ * whenever we are ready for more data. Shared logic independent of
+ * who is initiating the connection.
*
- * @param c Configuration handle.
+ * @param destination where to go
+ * @param path which path to take (may not be the full path)
+ * @param off offset of @a destination on @a path
+ * @param options options for the connection
+ * @param ct which tunnel uses this connection
+ * @param init_state initial state for the connection
+ * @param ready_cb function to call when ready to transmit
+ * @param ready_cb_cls closure for @a cb
+ * @return handle to the connection
*/
-void
-GCC_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_relative_min (GNUNET_TIME_UNIT_SECONDS,
- refresh_connection_time);
- connections = GNUNET_CONTAINER_multishortmap_create (1024,
- GNUNET_YES);
-}
-
-
-/**
- * Destroy each connection on shutdown.
- *
- * @param cls Closure (unused).
- * @param key Current key code (CID, unused).
- * @param value Value in the hash map (`struct CadetConnection`)
- *
- * @return #GNUNET_YES, because we should continue to iterate
- */
-static int
-shutdown_iterator (void *cls,
- const struct GNUNET_ShortHashCode *key,
- void *value)
-{
- struct CadetConnection *c = value;
-
- c->state = CADET_CONNECTION_DESTROYED;
- GCC_destroy (c);
- return GNUNET_YES;
-}
-
-
-/**
- * Shut down the connections subsystem.
- */
-void
-GCC_shutdown (void)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down connections\n");
- GCC_check_connections ();
- GNUNET_CONTAINER_multishortmap_iterate (connections,
- &shutdown_iterator,
- NULL);
- GNUNET_CONTAINER_multishortmap_destroy (connections);
- connections = NULL;
-}
-
-
-/**
- * Create a connection.
- *
- * @param cid Connection ID (either created locally or imposed remotely).
- * @param t Tunnel this connection belongs to (or NULL for transit connections);
- * @param path Path this connection has to use (copy is made).
- * @param own_pos Own position in the @c path path.
- *
- * @return Newly created connection.
- * NULL in case of error: own id not in path, wrong neighbors, ...
-*/
-struct CadetConnection *
-GCC_new (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
- struct CadetTunnel *t,
- struct CadetPeerPath *path,
- unsigned int own_pos)
-{
- struct CadetConnection *c;
- struct CadetPeerPath *cpath;
-
- GCC_check_connections ();
- cpath = path_duplicate (path);
- GNUNET_assert (NULL != cpath);
- c = GNUNET_new (struct CadetConnection);
- c->id = *cid;
+static struct CadetConnection *
+connection_create (struct CadetPeer *destination,
+ struct CadetPeerPath *path,
+ unsigned int off,
+ enum GNUNET_CADET_ChannelOption options,
+ struct CadetTConnection *ct,
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+ enum CadetConnectionState init_state,
+ GCC_ReadyCallback ready_cb,
+ void *ready_cb_cls)
+{
+ struct CadetConnection *cc;
+ struct CadetPeer *first_hop;
+
+ cc = GNUNET_new (struct CadetConnection);
+ cc->options = options;
+ cc->state = init_state;
+ cc->ct = ct;
+ cc->cid = *cid;
GNUNET_assert (GNUNET_OK ==
GNUNET_CONTAINER_multishortmap_put (connections,
- &c->id.connection_of_tunnel,
- c,
+ &GCC_get_id (cc)->connection_of_tunnel,
+ cc,
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 <= cpath->length - 1);
- c->own_pos = own_pos;
- c->path = cpath;
- cpath->c = c;
- if (GNUNET_OK != register_neighbors (c))
- {
- if (0 == own_pos)
- {
- /* We were the origin of this request, this means we have invalid
- * info about the paths to reach the destination. We must invalidate
- * the *original* path to avoid trying it again in the next minute.
- */
- if (2 < path->length)
- path_invalidate (path);
- else
- {
- GNUNET_break (0);
- GCT_debug(t, GNUNET_ERROR_TYPE_WARNING);
- }
- c->t = NULL;
- }
- path_destroy (c->path);
- c->path = NULL;
- GCC_destroy (c);
- return NULL;
- }
- LOG (GNUNET_ERROR_TYPE_INFO, "New connection %s\n", GCC_2s (c));
- GCC_check_connections ();
- return c;
-}
-
-
-/**
- * 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
-GCC_destroy (struct CadetConnection *c)
-{
- GCC_check_connections ();
- if (NULL == c)
- {
- GNUNET_break (0);
- return;
- }
-
- if (2 == c->destroy) /* cancel queues -> GCP_queue_cancel -> q_destroy -> */
- return; /* -> message_sent -> GCC_destroy. Don't loop. */
- c->destroy = 2;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "destroying connection %s\n",
- GCC_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);
- if (NULL != c->maintenance_q)
- {
- GCP_send_cancel (c->maintenance_q);
- c->maintenance_q = NULL;
- }
- }
- unregister_neighbors (c);
- path_destroy (c->path);
- c->path = NULL;
-
- /* Delete from tunnel */
- if (NULL != c->t)
- GCT_remove_connection (c->t, c);
-
- if (NULL != c->check_duplicates_task)
- GNUNET_SCHEDULER_cancel (c->check_duplicates_task);
- if (NULL != c->fwd_maintenance_task)
- GNUNET_SCHEDULER_cancel (c->fwd_maintenance_task);
- if (NULL != c->bck_maintenance_task)
- GNUNET_SCHEDULER_cancel (c->bck_maintenance_task);
-
- if (GNUNET_NO == c->was_removed)
- {
- GNUNET_break (GNUNET_YES ==
- GNUNET_CONTAINER_multishortmap_remove (connections,
- &c->id.connection_of_tunnel,
- c));
- }
- GNUNET_STATISTICS_update (stats,
- "# connections",
- -1,
- GNUNET_NO);
- GNUNET_free (c);
- GCC_check_connections ();
-}
-
-
-/**
- * Get the connection ID.
- *
- * @param c Connection to get the ID from.
- *
- * @return ID of the connection.
- */
-const struct GNUNET_CADET_ConnectionTunnelIdentifier *
-GCC_get_id (const struct CadetConnection *c)
-{
- return &c->id;
-}
-
-
-/**
- * Get the connection path.
- *
- * @param c Connection to get the path from.
- *
- * @return path used by the connection.
- */
-const struct CadetPeerPath *
-GCC_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
-GCC_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 CadetTunnel *
-GCC_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
-GCC_get_buffer (struct CadetConnection *c, int fwd)
-{
- struct CadetFlowControl *fc;
-
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Get %s buffer on %s: %u - %u\n",
- GC_f2s (fwd), GCC_2s (c), fc->queue_max, fc->queue_n);
- GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG);
-
- 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
-GCC_get_allowed (struct CadetConnection *c, int fwd)
-{
- struct CadetFlowControl *fc;
-
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
- if ( (CADET_CONNECTION_READY != c->state) ||
- GC_is_pid_bigger (ntohl (fc->last_pid_recv.pid),
- ntohl (fc->last_ack_sent.pid)) )
- {
- return 0;
- }
- return (ntohl (fc->last_ack_sent.pid) - ntohl (fc->last_pid_recv.pid));
-}
-
-
-/**
- * Get messages queued in a connection.
- *
- * @param c Connection.
- * @param fwd Is query about FWD traffic?
- *
- * @return Number of messages queued.
- */
-unsigned int
-GCC_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 Next PID to use.
- */
-struct CadetEncryptedMessageIdentifier
-GCC_get_pid (struct CadetConnection *c, int fwd)
-{
- struct CadetFlowControl *fc;
- struct CadetEncryptedMessageIdentifier pid;
-
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
- pid = fc->next_pid;
- fc->next_pid.pid = htonl (1 + ntohl (pid.pid));
- return pid;
-}
-
-
-/**
- * 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
-GCC_allow (struct CadetConnection *c, unsigned int buffer, int fwd)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " allowing %s %u messages %s\n",
- GCC_2s (c), buffer, GC_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
-GCC_neighbor_disconnected (struct CadetConnection *c, struct CadetPeer *peer)
-{
- struct CadetFlowControl *fc;
- char peer_name[16];
- int fwd;
-
- GCC_check_connections ();
- strncpy (peer_name, GCP_2s (peer), 16);
- peer_name[15] = '\0';
+ cc->ready_cb = ready_cb;
+ cc->ready_cb_cls = ready_cb_cls;
+ cc->path = path;
+ cc->off = off;
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "shutting down %s, %s disconnected\n",
- GCC_2s (c), peer_name);
-
- invalidate_paths (c, peer);
-
- fwd = is_fwd (c, peer);
- if (GNUNET_SYSERR == fwd)
- {
- GNUNET_break (0);
- return;
- }
- if ( (GNUNET_YES == GCC_is_terminal (c, fwd)) ||
- (GNUNET_NO != c->destroy) )
- {
- /* Local shutdown, or other peer already down (hence 'c->destroy');
- so there is no one to notify about this, just clean up. */
- GCC_destroy (c);
- GCC_check_connections ();
- return;
- }
- /* Mark FlowControl towards the peer as unavaliable. */
- fc = fwd ? &c->bck_fc : &c->fwd_fc;
- fc->queue_max = 0;
-
- send_broken (c, &my_full_id, GCP_get_id (peer), fwd);
-
- /* Connection will have at least one pending message
- * (the one we just scheduled), so delay destruction
- * and remove from map so we don't use accidentally. */
- mark_destroyed (c);
- GNUNET_assert (GNUNET_NO == c->was_removed);
- c->was_removed = GNUNET_YES;
- GNUNET_break (GNUNET_YES ==
- GNUNET_CONTAINER_multishortmap_remove (connections,
- &c->id.connection_of_tunnel,
- c));
- /* Cancel queue in the direction that just died. */
- connection_cancel_queues (c, ! fwd);
- GCC_stop_poll (c, ! fwd);
- unregister_neighbors (c);
- GCC_check_connections ();
-}
-
-
-/**
- * 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.
+ "Creating %s using path %s\n",
+ GCC_2s (cc),
+ GCPP_2s (path));
+ GCPP_add_connection (path,
+ off,
+ cc);
+ for (unsigned int i=0;i<off;i++)
+ GCP_add_connection (GCPP_get_peer_at_offset (path,
+ i),
+ cc);
+
+ first_hop = GCPP_get_peer_at_offset (path,
+ 0);
+ cc->mq_man = GCP_request_mq (first_hop,
+ &manage_first_hop_mq,
+ cc);
+ return cc;
+}
+
+
+/**
+ * Create a connection to @a destination via @a path and
+ * notify @a cb whenever we are ready for more data. This
+ * is an inbound tunnel, so we must use the existing @a cid
+ *
+ * @param destination where to go
+ * @param path which path to take (may not be the full path)
+ * @param options options for the connection
+ * @param ct which tunnel uses this connection
+ * @param ready_cb function to call when ready to transmit
+ * @param ready_cb_cls closure for @a cb
+ * @return handle to the connection, NULL if we already have
+ * a connection that takes precedence on @a path
*/
-int
-GCC_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
-GCC_is_terminal (struct CadetConnection *c, int fwd)
-{
- return GCC_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
-GCC_is_sendable (struct CadetConnection *c, int fwd)
-{
- struct CadetFlowControl *fc;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " checking sendability of %s traffic on %s\n",
- GC_f2s (fwd), GCC_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",
- ntohl (fc->last_ack_recv.pid),
- ntohl (fc->last_pid_sent.pid));
- if (GC_is_pid_bigger (ntohl (fc->last_ack_recv.pid),
- ntohl (fc->last_pid_sent.pid)))
- {
- 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
-GCC_is_direct (struct CadetConnection *c)
-{
- return (c->path->length == 2) ? GNUNET_YES : GNUNET_NO;
-}
-
-
-/**
- * Sends a completely built message on a connection, properly registering
- * all used resources.
- *
- * @param message Message to send.
- * @param payload_type Type of payload, in case the message is encrypted.
- * 0 for restransmissions (when type is no longer known)
- * UINT16_MAX when not applicable.
- * @param payload_id ID of the payload (PID, ACK, ...).
- * @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.
- * Invalid on @c cont call.
- */
-struct CadetConnectionQueue *
-GCC_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
- uint16_t payload_type,
- struct CadetEncryptedMessageIdentifier payload_id,
- struct CadetConnection *c, int fwd, int force,
- GCC_sent cont, void *cont_cls)
-{
- struct CadetFlowControl *fc;
- struct CadetConnectionQueue *q;
- uint16_t size;
- uint16_t type;
-
- size = ntohs (message->size);
- type = ntohs (message->type);
-
- GCC_check_connections ();
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
- if (0 == fc->queue_max)
- {
- GNUNET_break (0);
- return NULL;
- }
-
- LOG (GNUNET_ERROR_TYPE_INFO,
- "--> %s (%s %4u) on conn %s (%p) %s [%5u]\n",
- GC_m2s (type), GC_m2s (payload_type), payload_id, GCC_2s (c), c,
- GC_f2s(fwd), size);
- switch (type)
- {
- case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED:
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Q_N+ %p %u, PIDsnt: %u, ACKrcv: %u\n",
- fc,
- fc->queue_n,
- ntohl (fc->last_pid_sent.pid),
- ntohl (fc->last_ack_recv.pid));
- if (GNUNET_NO == force)
- {
- fc->queue_n++;
- }
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX:
- /* nothing to do here */
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK:
- /* Should've only be used for restransmissions. */
- GNUNET_break (0 == payload_type);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
- GNUNET_assert (GNUNET_YES == force);
- break;
-
- default:
- GNUNET_break (0);
+struct CadetConnection *
+GCC_create_inbound (struct CadetPeer *destination,
+ struct CadetPeerPath *path,
+ enum GNUNET_CADET_ChannelOption options,
+ struct CadetTConnection *ct,
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+ GCC_ReadyCallback ready_cb,
+ void *ready_cb_cls)
+{
+ struct CadetConnection *cc;
+ unsigned int off;
+
+ off = GCPP_find_peer (path,
+ destination);
+ GNUNET_assert (UINT_MAX != off);
+ cc = GCPP_get_connection (path,
+ destination,
+ off);
+ if (NULL != cc)
+ {
+ int cmp;
+
+ cmp = memcmp (cid,
+ &cc->cid,
+ sizeof (*cid));
+ if (0 == cmp)
+ {
+ /* Two peers picked the SAME random connection identifier at the
+ same time for the same path? Must be malicious. Drop
+ connection (existing and inbound), even if it is the only
+ one. */
+ GNUNET_break_op (0);
+ GCT_connection_lost (cc->ct);
+ GCC_destroy_without_tunnel (cc);
return NULL;
- }
-
- if (fc->queue_n > fc->queue_max && GNUNET_NO == force)
- {
- 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_TUNNEL_ENCRYPTED == type)
+ }
+ if (0 < cmp)
{
- fc->queue_n--;
+ /* drop existing */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Got two connections on %s, dropping my existing %s\n",
+ GCPP_2s (path),
+ GCC_2s (cc));
+ GCT_connection_lost (cc->ct);
+ GCC_destroy_without_tunnel (cc);
}
- return NULL; /* Drop this message */
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %s %u\n",
- GCC_2s (c), c->pending_messages);
- c->pending_messages++;
-
- q = GNUNET_new (struct CadetConnectionQueue);
- q->cont = cont;
- q->cont_cls = cont_cls;
- q->forced = force;
- GNUNET_CONTAINER_DLL_insert (fc->q_head, fc->q_tail, q);
- q->peer_q = GCP_send (get_hop (c, fwd),
- message,
- payload_type,
- payload_id,
- c,
- fwd,
- &conn_message_sent, q);
- if (NULL == q->peer_q)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "dropping msg on %s, NULL q\n", GCC_2s (c));
- GNUNET_CONTAINER_DLL_remove (fc->q_head, fc->q_tail, q);
- GNUNET_free (q);
- GCC_check_connections ();
- return NULL;
- }
- GCC_check_connections ();
- return 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
-GCC_cancel (struct CadetConnectionQueue *q)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "! GCC cancel message\n");
-
- /* send_cancel calls message_sent, which calls q->cont and frees q */
- GCP_send_cancel (q->peer_q);
- GCC_check_connections ();
-}
-
-
-/**
- * Sends a CREATE CONNECTION message for a path to a peer.
- * Changes the connection and tunnel states if necessary.
- *
- * @param c Connection to create.
- */
-void
-GCC_send_create (struct CadetConnection *c)
-{
- static struct CadetEncryptedMessageIdentifier zero;
- enum CadetTunnelCState state;
- size_t size;
-
- GCC_check_connections ();
- size = sizeof (struct GNUNET_CADET_ConnectionCreateMessage);
- size += c->path->length * sizeof (struct GNUNET_PeerIdentity);
- {
- /* Allocate message on the stack */
- unsigned char cbuf[size];
- struct GNUNET_CADET_ConnectionCreateMessage *msg;
- struct GNUNET_PeerIdentity *peers;
-
-
- msg = (struct GNUNET_CADET_ConnectionCreateMessage *) cbuf;
- msg->header.size = htons (size);
- msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE);
- msg->options = htonl (0);
- msg->cid = *GCC_get_id (c);
- peers = (struct GNUNET_PeerIdentity *) &msg[1];
- for (int i = 0; i < c->path->length; i++)
+ else
{
- GNUNET_PEER_resolve (c->path->peers[i], peers++);
+ /* keep existing */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Got two connections on %s, keeping my existing %s\n",
+ GCPP_2s (path),
+ GCC_2s (cc));
+ return NULL;
}
- GNUNET_assert (NULL == c->maintenance_q);
- c->maintenance_q = GCP_send (get_next_hop (c),
- &msg->header,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE,
- zero,
- c, GNUNET_YES,
- &conn_message_sent, NULL);
}
- LOG (GNUNET_ERROR_TYPE_INFO, "==> %s %19s on conn %s (%p) FWD [%5u]\n",
- GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE), "",
- GCC_2s (c), c, size);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %p %u (create)\n",
- c, c->pending_messages);
- c->pending_messages++;
-
- state = GCT_get_cstate (c->t);
- if (CADET_TUNNEL_SEARCHING == state || CADET_TUNNEL_NEW == state)
- GCT_change_cstate (c->t, CADET_TUNNEL_WAITING);
- if (CADET_CONNECTION_NEW == c->state)
- connection_change_state (c, CADET_CONNECTION_SENT);
- GCC_check_connections ();
+ return connection_create (destination,
+ path,
+ off,
+ options,
+ ct,
+ cid,
+ CADET_CONNECTION_CREATE_RECEIVED,
+ ready_cb,
+ ready_cb_cls);
}
/**
- * Send an ACK on the appropriate connection/channel, depending on
- * the direction and the position of the peer.
+ * Create a connection to @a destination via @a path and
+ * notify @a cb whenever we are ready for more data.
*
- * @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).
+ * @param destination where to go
+ * @param path which path to take (may not be the full path)
+ * @param off offset of @a destination on @a path
+ * @param options options for the connection
+ * @param ct tunnel that uses the connection
+ * @param ready_cb function to call when ready to transmit
+ * @param ready_cb_cls closure for @a cb
+ * @return handle to the connection
*/
-void
-GCC_send_ack (struct CadetConnection *c, int fwd, int force)
+struct CadetConnection *
+GCC_create (struct CadetPeer *destination,
+ struct CadetPeerPath *path,
+ unsigned int off,
+ enum GNUNET_CADET_ChannelOption options,
+ struct CadetTConnection *ct,
+ GCC_ReadyCallback ready_cb,
+ void *ready_cb_cls)
{
- unsigned int buffer;
-
- GCC_check_connections ();
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GCC send %s ACK on %s\n",
- GC_f2s (fwd), GCC_2s (c));
-
- if (NULL == c)
- {
- GNUNET_break (0);
- return;
- }
+ struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
- if (GNUNET_NO != c->destroy)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " being destroyed, why bother...\n");
- GCC_check_connections ();
- return;
- }
-
- /* Get available buffer space */
- if (GCC_is_terminal (c, fwd))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " getting from all channels\n");
- buffer = GCT_get_channels_buffer (c->t);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " getting from one connection\n");
- buffer = GCC_get_buffer (c, fwd);
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer available: %u\n", buffer);
- if (0 == buffer && GNUNET_NO == force)
- {
- GCC_check_connections ();
- return;
- }
-
- /* Send available buffer space */
- if (GNUNET_YES == GCC_is_origin (c, fwd))
- {
- GNUNET_assert (NULL != c->t);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channels...\n");
- GCT_unchoke_channels (c->t);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on connection\n");
- send_ack (c, buffer, fwd, force);
- }
- GCC_check_connections ();
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+ &cid,
+ sizeof (cid));
+ return connection_create (destination,
+ path,
+ off,
+ options,
+ ct,
+ &cid,
+ CADET_CONNECTION_NEW,
+ ready_cb,
+ ready_cb_cls);
}
/**
- * Send a message to all peers in this connection that the connection
- * is no longer valid.
+ * Transmit message @a msg via connection @a cc. Must only be called
+ * (once) after the connection has signalled that it is ready via the
+ * `ready_cb`. Clients can also use #GCC_is_ready() to check if the
+ * connection is right now ready for transmission.
*
- * 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.
+ * @param cc connection identification
+ * @param env envelope with message to transmit; must NOT
+ * yet have a #GNUNET_MQ_notify_sent() callback attached to it
*/
void
-GCC_send_destroy (struct CadetConnection *c)
+GCC_transmit (struct CadetConnection *cc,
+ struct GNUNET_MQ_Envelope *env)
{
- static struct CadetEncryptedMessageIdentifier zero;
- struct GNUNET_CADET_ConnectionDestroyMessage msg;
-
- if (GNUNET_YES == c->destroy)
- return;
- GCC_check_connections ();
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);
- msg.cid = c->id;
- msg.reserved = htonl (0);
LOG (GNUNET_ERROR_TYPE_DEBUG,
- " sending connection destroy for connection %s\n",
- GCC_2s (c));
-
- if (GNUNET_NO == GCC_is_terminal (c, GNUNET_YES))
- (void) GCC_send_prebuilt_message (&msg.header,
- UINT16_MAX,
- zero,
- c,
- GNUNET_YES, GNUNET_YES, NULL, NULL);
- if (GNUNET_NO == GCC_is_terminal (c, GNUNET_NO))
- (void) GCC_send_prebuilt_message (&msg.header,
- UINT16_MAX,
- zero,
- c,
- GNUNET_NO, GNUNET_YES, NULL, NULL);
- mark_destroyed (c);
- GCC_check_connections ();
+ "Scheduling message for transmission on %s\n",
+ GCC_2s (cc));
+ GNUNET_assert (GNUNET_YES == cc->mqm_ready);
+ GNUNET_assert (CADET_CONNECTION_READY == cc->state);
+ cc->metrics.last_use = GNUNET_TIME_absolute_get ();
+ cc->mqm_ready = GNUNET_NO;
+ if (NULL != cc->task)
+ {
+ GNUNET_SCHEDULER_cancel (cc->task);
+ cc->task = NULL;
+ }
+ GCP_send (cc->mq_man,
+ env);
}
/**
- * @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.
+ * Obtain the path used by this connection.
*
- * @param c Connection.
- * @param fwd Should we poll in the FWD direction?
+ * @param cc connection
+ * @return path to @a cc
*/
-void
-GCC_start_poll (struct CadetConnection *c, int fwd)
+struct CadetPeerPath *
+GCC_get_path (struct CadetConnection *cc)
{
- struct CadetFlowControl *fc;
-
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL %s requested\n",
- GC_f2s (fwd));
- if (NULL != fc->poll_task || NULL != fc->poll_msg)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " POLL already in progress (t: %p, m: %p)\n",
- fc->poll_task, fc->poll_msg);
- return;
- }
- if (0 == fc->queue_max)
- {
- /* Should not be needed, traffic should've been cancelled. */
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " POLL not possible, peer disconnected\n");
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL started on request\n");
- fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time, &send_poll, fc);
+ return cc->path;
}
/**
- * @brief Stop polling a connection for ACKs.
+ * Obtain unique ID for the connection.
*
- * 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?
+ * @param cc connection.
+ * @return unique number of the connection
*/
-void
-GCC_stop_poll (struct CadetConnection *c, int fwd)
+const struct GNUNET_CADET_ConnectionTunnelIdentifier *
+GCC_get_id (struct CadetConnection *cc)
{
- struct CadetFlowControl *fc;
-
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
- if (NULL != fc->poll_task)
- {
- GNUNET_SCHEDULER_cancel (fc->poll_task);
- fc->poll_task = NULL;
- }
- if (NULL != fc->poll_msg)
- {
- GCC_cancel (fc->poll_msg);
- fc->poll_msg = NULL;
- }
+ return &cc->cid;
}
/**
* Get a (static) string for a connection.
*
- * @param c Connection.
+ * @param cc Connection.
*/
const char *
-GCC_2s (const struct CadetConnection *c)
+GCC_2s (const struct CadetConnection *cc)
{
- if (NULL == c)
- return "NULL";
+ static char buf[128];
- if (NULL != c->t)
- {
- static char buf[128];
+ if (NULL == cc)
+ return "Connection(NULL)";
- SPRINTF (buf, "%s (->%s)",
- GNUNET_sh2s (&GCC_get_id (c)->connection_of_tunnel),
- GCT_2s (c->t));
+ if (NULL != cc->ct)
+ {
+ GNUNET_snprintf (buf,
+ sizeof (buf),
+ "Connection %s (%s)",
+ GNUNET_sh2s (&cc->cid.connection_of_tunnel),
+ GCT_2s (cc->ct->t));
return buf;
}
- return GNUNET_sh2s (&c->id.connection_of_tunnel);
+ GNUNET_snprintf (buf,
+ sizeof (buf),
+ "Connection %s",
+ GNUNET_sh2s (&cc->cid.connection_of_tunnel));
+ return buf;
}
+#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-con",__VA_ARGS__)
+
+
/**
- * Log all possible info about the connection state.
+ * Log connection info.
*
- * @param c Connection to debug.
+ * @param cc connection
* @param level Debug level to use.
*/
void
-GCC_debug (const struct CadetConnection *c, enum GNUNET_ErrorType level)
+GCC_debug (struct CadetConnection *cc,
+ enum GNUNET_ErrorType level)
{
int do_log;
- char *s;
do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
"cadet-con",
__FILE__, __FUNCTION__, __LINE__);
if (0 == do_log)
return;
-
- if (NULL == c)
+ if (NULL == cc)
{
- LOG2 (level, "CCC DEBUG NULL CONNECTION\n");
+ LOG2 (level,
+ "Connection (NULL)\n");
return;
}
-
- LOG2 (level, "CCC DEBUG CONNECTION %s\n", GCC_2s (c));
- s = path_2s (c->path);
- LOG2 (level, "CCC path %s, own pos: %u\n", s, c->own_pos);
- GNUNET_free (s);
- LOG2 (level, "CCC state: %s, destroy: %u\n",
- GCC_state2s (c->state), c->destroy);
- LOG2 (level, "CCC pending messages: %u\n", c->pending_messages);
- if (NULL != c->perf)
- LOG2 (level, "CCC us/byte: %f\n", c->perf->avg);
-
- LOG2 (level, "CCC FWD flow control:\n");
- LOG2 (level, "CCC queue: %u/%u\n", c->fwd_fc.queue_n, c->fwd_fc.queue_max);
- LOG2 (level, "CCC last PID sent: %5u, recv: %5u\n",
- ntohl (c->fwd_fc.last_pid_sent.pid),
- ntohl (c->fwd_fc.last_pid_recv.pid));
- LOG2 (level, "CCC last ACK sent: %5u, recv: %5u\n",
- ntohl (c->fwd_fc.last_ack_sent.pid),
- ntohl (c->fwd_fc.last_ack_recv.pid));
- LOG2 (level, "CCC recv PID bitmap: %X\n", c->fwd_fc.recv_bitmap);
- LOG2 (level, "CCC poll: task %d, msg %p, msg_ack %p)\n",
- c->fwd_fc.poll_task, c->fwd_fc.poll_msg, c->fwd_fc.ack_msg);
-
- LOG2 (level, "CCC BCK flow control:\n");
- LOG2 (level, "CCC queue: %u/%u\n", c->bck_fc.queue_n, c->bck_fc.queue_max);
- LOG2 (level, "CCC last PID sent: %5u, recv: %5u\n",
- ntohl (c->bck_fc.last_pid_sent.pid),
- ntohl (c->bck_fc.last_pid_recv.pid));
- LOG2 (level, "CCC last ACK sent: %5u, recv: %5u\n",
- ntohl (c->bck_fc.last_ack_sent.pid),
- ntohl (c->bck_fc.last_ack_recv.pid));
- LOG2 (level, "CCC recv PID bitmap: %X\n", c->bck_fc.recv_bitmap);
- LOG2 (level, "CCC poll: task %d, msg %p, msg_ack %p)\n",
- c->bck_fc.poll_task, c->bck_fc.poll_msg, c->bck_fc.ack_msg);
-
- LOG2 (level, "CCC DEBUG CONNECTION END\n");
+ LOG2 (level,
+ "%s to %s via path %s in state %d is %s\n",
+ GCC_2s (cc),
+ GCP_2s (cc->destination),
+ GCPP_2s (cc->path),
+ cc->state,
+ (GNUNET_YES == cc->mqm_ready) ? "ready" : "busy");
}
+
+/* end of gnunet-service-cadet-new_connection.c */
diff --git a/src/cadet/gnunet-service-cadet_connection.h b/src/cadet/gnunet-service-cadet_connection.h
index 307cb42c2b..fdb1843661 100644
--- a/src/cadet/gnunet-service-cadet_connection.h
+++ b/src/cadet/gnunet-service-cadet_connection.h
@@ -1,6 +1,7 @@
+
/*
This file is part of GNUnet.
- Copyright (C) 2013 GNUnet e.V.
+ Copyright (C) 2001-2017 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
@@ -20,557 +21,319 @@
/**
* @file cadet/gnunet-service-cadet_connection.h
- * @brief cadet service; dealing with connections
+ * @brief A connection is a live end-to-end messaging mechanism
+ * where the peers are identified by a path and know how
+ * to forward along the route using a connection identifier
+ * for routing the data.
* @author Bartlomiej Polot
- *
- * All functions in this file use the prefix GCC (GNUnet Cadet Connection)
+ * @author Christian Grothoff
*/
-
#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,
-
- /**
- * Connection to be destroyed because of a distant peer, same as DESTROYED.
- */
- CADET_CONNECTION_BROKEN,
-};
-
-
-/**
- * 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.h"
#include "gnunet-service-cadet_peer.h"
+#include "cadet_protocol.h"
/**
- * Check invariants for all connections using #check_neighbours().
- */
-void
-GCC_check_connections (void);
-
-
-/**
- * Callback called when a queued message is sent.
+ * Function called to notify tunnel about change in our readyness.
*
- * @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.
+ * @param cls closure
+ * @param is_ready #GNUNET_YES if the connection is now ready for transmission,
+ * #GNUNET_NO if the connection is no longer ready for transmission
*/
typedef void
-(*GCC_sent) (void *cls,
- struct CadetConnection *c,
- struct CadetConnectionQueue *q,
- uint16_t type,
- int fwd,
- size_t size);
+(*GCC_ReadyCallback)(void *cls,
+ int is_ready);
/**
- * Handler for connection creation.
+ * Destroy a connection, called when the CORE layer is already done
+ * (i.e. has received a BROKEN message), but if we still have to
+ * communicate the destruction of the connection to the tunnel (if one
+ * exists).
*
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param cc connection to destroy
*/
void
-GCC_handle_create (struct CadetPeer *peer,
- const struct GNUNET_CADET_ConnectionCreateMessage *msg);
+GCC_destroy_without_core (struct CadetConnection *cc);
/**
- * Handler for connection confirmations.
+ * Destroy a connection, called if the tunnel association with the
+ * connection was already broken, but we still need to notify the CORE
+ * layer about the breakage.
*
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param cc connection to destroy
*/
void
-GCC_handle_confirm (struct CadetPeer *peer,
- const struct GNUNET_CADET_ConnectionCreateAckMessage *msg);
+GCC_destroy_without_tunnel (struct CadetConnection *cc);
/**
- * Handler for notifications of broken connections.
+ * Lookup a connection by its identifier.
*
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param cid identifier to resolve
+ * @return NULL if connection was not found
*/
-void
-GCC_handle_broken (struct CadetPeer *peer,
- const struct GNUNET_CADET_ConnectionBrokenMessage *msg);
+struct CadetConnection *
+GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
-/**
- * Handler for notifications of destroyed connections.
- *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
- */
-void
-GCC_handle_destroy (struct CadetPeer *peer,
- const struct GNUNET_CADET_ConnectionDestroyMessage *msg);
/**
- * Handler for cadet network traffic hop-by-hop acks.
+ * Create a connection to @a destination via @a path and
+ * notify @a cb whenever we are ready for more data.
*
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param destination where to go
+ * @param path which path to take (may not be the full path)
+ * @param off offset of @a destination on @a path
+ * @param options options for the connection
+ * @param ct which tunnel uses this connection
+ * @param ready_cb function to call when ready to transmit
+ * @param ready_cb_cls closure for @a cb
+ * @return handle to the connection
*/
-void
-GCC_handle_ack (struct CadetPeer *peer,
- const struct GNUNET_CADET_ConnectionEncryptedAckMessage *msg);
+struct CadetConnection *
+GCC_create (struct CadetPeer *destination,
+ struct CadetPeerPath *path,
+ unsigned int off,
+ enum GNUNET_CADET_ChannelOption options,
+ struct CadetTConnection *ct,
+ GCC_ReadyCallback ready_cb,
+ void *ready_cb_cls);
-/**
- * Handler for cadet network traffic hop-by-hop data counter polls.
- *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
- */
-void
-GCC_handle_poll (struct CadetPeer *peer,
- const struct GNUNET_CADET_ConnectionHopByHopPollMessage *msg);
/**
- * Handler for key exchange traffic (Axolotl KX).
+ * Create a connection to @a destination via @a path and
+ * notify @a cb whenever we are ready for more data. This
+ * is an inbound tunnel, so we must use the existing @a cid
*
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param destination where to go
+ * @param path which path to take (may not be the full path)
+ * @param options options for the connection
+ * @param ct which tunnel uses this connection
+ * @param ready_cb function to call when ready to transmit
+ * @param ready_cb_cls closure for @a cb
+ * @return handle to the connection, NULL if we already have
+ * a connection that takes precedence on @a path
*/
-void
-GCC_handle_kx (struct CadetPeer *peer,
- const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg);
+struct CadetConnection *
+GCC_create_inbound (struct CadetPeer *destination,
+ struct CadetPeerPath *path,
+ enum GNUNET_CADET_ChannelOption options,
+ struct CadetTConnection *ct,
+ const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+ GCC_ReadyCallback ready_cb,
+ void *ready_cb_cls);
+
/**
- * Handler for encrypted cadet network traffic (channel mgmt, data).
+ * Transmit message @a msg via connection @a cc. Must only be called
+ * (once) after the connection has signalled that it is ready via the
+ * `ready_cb`. Clients can also use #GCC_is_ready() to check if the
+ * connection is right now ready for transmission.
*
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param cc connection identification
+ * @param env envelope with message to transmit;
+ * the #GNUNET_MQ_notify_send() must not have yet been used
+ * for the envelope. Also, the message better match the
+ * connection identifier of this connection...
*/
void
-GCC_handle_encrypted (struct CadetPeer *peer,
- const struct GNUNET_CADET_TunnelEncryptedMessage *msg);
+GCC_transmit (struct CadetConnection *cc,
+ struct GNUNET_MQ_Envelope *env);
-/**
- * Core handler for axolotl key exchange traffic.
- *
- * @param cls Closure (unused).
- * @param message Message received.
- * @param peer Neighbor who sent the message.
- *
- * @return GNUNET_OK, to keep the connection open.
- */
-int
-GCC_handle_ax_kx (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message);
/**
- * Core handler for axolotl encrypted cadet network traffic.
+ * A CREATE_ACK was received for this connection, process it.
*
- * @param cls Closure (unused).
- * @param message Message received.
- * @param peer Neighbor who sent the message.
- *
- * @return GNUNET_OK, to keep the connection open.
+ * @param cc the connection that got the ACK.
*/
-int
-GCC_handle_ax (void *cls, const struct GNUNET_PeerIdentity *peer,
- struct GNUNET_MessageHeader *message);
+void
+GCC_handle_connection_create_ack (struct CadetConnection *cc);
-/**
- * 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
-GCC_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.
+ * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a
+ * connection that we already have. Either our ACK got lost
+ * or something is fishy. Consider retransmitting the ACK.
*
- * @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).
+ * @param cc connection that got the duplicate CREATE
*/
void
-GCC_send_ack (struct CadetConnection *c, int fwd, int force);
+GCC_handle_duplicate_create (struct CadetConnection *cc);
-/**
- * Initialize the connections subsystem
- *
- * @param c Configuration handle.
- */
-void
-GCC_init (const struct GNUNET_CONFIGURATION_Handle *c);
/**
- * Shut down the connections subsystem.
+ * Handle KX message.
+ *
+ * @param cc connection that received encrypted message
+ * @param msg the key exchange message
*/
void
-GCC_shutdown (void);
+GCC_handle_kx (struct CadetConnection *cc,
+ const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg);
-/**
- * Create a connection.
- *
- * @param cid Connection ID (either created locally or imposed remotely).
- * @param t Tunnel this connection belongs to (or NULL for transit connections);
- * @param path Path this connection has to use (copy is made).
- * @param own_pos Own position in the @c path path.
- *
- * @return Newly created connection.
- * NULL in case of error: own id not in path, wrong neighbors, ...
- */
-struct CadetConnection *
-GCC_new (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
- struct CadetTunnel *t,
- struct CadetPeerPath *path,
- 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.
+ * Handle KX_AUTH message.
*
- * @param c Connection to destroy.
+ * @param cc connection that received encrypted message
+ * @param msg the key exchange message
*/
void
-GCC_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_ConnectionTunnelIdentifier *
-GCC_get_id (const struct CadetConnection *c);
+GCC_handle_kx_auth (struct CadetConnection *cc,
+ const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg);
/**
- * Get the connection path.
- *
- * @param c Connection to get the path from.
- *
- * @return path used by the connection.
+ * Performance metrics for a connection.
*/
-const struct CadetPeerPath *
-GCC_get_path (const struct CadetConnection *c);
+struct CadetConnectionMetrics
+{
-/**
- * Get the connection state.
- *
- * @param c Connection to get the state from.
- *
- * @return state of the connection.
- */
-enum CadetConnectionState
-GCC_get_state (const struct CadetConnection *c);
+ /**
+ * Our current best estimate of the latency, based on a weighted
+ * average of at least @a latency_datapoints values.
+ */
+ struct GNUNET_TIME_Relative aged_latency;
-/**
- * Get the connection tunnel.
- *
- * @param c Connection to get the tunnel from.
- *
- * @return tunnel of the connection.
- */
-struct CadetTunnel *
-GCC_get_tunnel (const struct CadetConnection *c);
+ /**
+ * When was this connection first established? (by us sending or
+ * receiving the CREATE_ACK for the first time)
+ */
+ struct GNUNET_TIME_Absolute age;
-/**
- * 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
-GCC_get_buffer (struct CadetConnection *c, int fwd);
+ /**
+ * When was this connection last used? (by us sending or
+ * receiving a PAYLOAD message on it)
+ */
+ struct GNUNET_TIME_Absolute last_use;
-/**
- * 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
-GCC_get_allowed (struct CadetConnection *c, int fwd);
+ /**
+ * How many packets that ought to generate an ACK did we send via
+ * this connection?
+ */
+ unsigned long long num_acked_transmissions;
-/**
- * Get messages queued in a connection.
- *
- * @param c Connection.
- * @param fwd Is query about FWD traffic?
- *
- * @return Number of messages queued.
- */
-unsigned int
-GCC_get_qn (struct CadetConnection *c, int fwd);
+ /**
+ * Number of packets that were sent via this connection did actually
+ * receive an ACK? (Note: ACKs may be transmitted and lost via
+ * other connections, so this value should only be interpreted
+ * relative to @e num_acked_transmissions and in relation to other
+ * connections.)
+ */
+ unsigned long long num_successes;
-/**
- * Get next PID to use.
- *
- * @param c Connection.
- * @param fwd Is query about FWD traffic?
- * @return Next PID to use.
- */
-struct CadetEncryptedMessageIdentifier
-GCC_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
-GCC_allow (struct CadetConnection *c, unsigned int buffer, int fwd);
/**
- * Send FWD keepalive packets for a connection.
+ * Obtain performance @a metrics from @a cc.
*
- * @param cls Closure (connection for which to send the keepalive).
- * @param tc Notification context.
+ * @param cc connection to query
+ * @return the metrics
*/
-void
-GCC_fwd_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+const struct CadetConnectionMetrics *
+GCC_get_metrics (struct CadetConnection *cc);
+
/**
- * Send BCK keepalive packets for a connection.
+ * Handle encrypted message.
*
- * @param cls Closure (connection for which to send the keepalive).
- * @param tc Notification context.
+ * @param cc connection that received encrypted message
+ * @param msg the encrypted message to decrypt
*/
void
-GCC_bck_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+GCC_handle_encrypted (struct CadetConnection *cc,
+ const struct GNUNET_CADET_TunnelEncryptedMessage *msg);
/**
- * Notify other peers on a connection of a broken link. Mark connections
- * to destroy after all traffic has been sent.
+ * We sent a message for which we expect to receive an ACK via
+ * the connection identified by @a cti.
*
- * @param c Connection on which there has been a disconnection.
- * @param peer Peer that disconnected.
+ * @param cid connection identifier where we expect an ACK
*/
void
-GCC_neighbor_disconnected (struct CadetConnection *c, struct CadetPeer *peer);
+GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
-/**
- * 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
-GCC_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!
+ * We observed an ACK for a message that was originally sent via
+ * the connection identified by @a cti.
*
- * @return #GNUNET_YES if terminal, #GNUNET_NO if relay/origin.
+ * @param cid connection identifier where we got an ACK for a message
+ * that was originally sent via this connection (the ACK
+ * may have gotten back to us via a different connection).
*/
-int
-GCC_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
-GCC_is_sendable (struct CadetConnection *c, int fwd);
+void
+GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
-/**
- * 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
-GCC_is_direct (struct CadetConnection *c);
/**
- * Cancel a previously sent message while it's in the queue.
+ * We observed some the given @a latency on the connection
+ * identified by @a cti. (The same connection was taken
+ * in both directions.)
*
- * 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.
+ * @param cti connection identifier where we measured latency
+ * @param latency the observed latency
*/
void
-GCC_cancel (struct CadetConnectionQueue *q);
+GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+ struct GNUNET_TIME_Relative latency);
-/**
- * Sends an already built message on a connection, properly registering
- * all used resources.
- *
- * @param message Message to send.
- * @param payload_type Type of payload, in case the message is encrypted.
- * 0 for restransmissions (when type is no longer known)
- * UINT16_MAX when not applicable.
- * @param payload_id ID of the payload (PID, ACK, ...).
- * @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.
- * Invalid on @c cont call.
- */
-struct CadetConnectionQueue *
-GCC_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
- uint16_t payload_type,
- struct CadetEncryptedMessageIdentifier payload_id,
- struct CadetConnection *c, int fwd, int force,
- GCC_sent cont, void *cont_cls);
/**
- * Sends a CREATE CONNECTION message for a path to a peer.
- * Changes the connection and tunnel states if necessary.
+ * Return the tunnel associated with this connection.
*
- * @param connection Connection to create.
+ * @param cc connection to query
+ * @return corresponding entry in the tunnel's connection list
*/
-void
-GCC_send_create (struct CadetConnection *connection);
+struct CadetTConnection *
+GCC_get_ct (struct CadetConnection *cc);
-/**
- * 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
-GCC_send_destroy (struct CadetConnection *c);
/**
- * @brief Start a polling timer for the connection.
+ * Obtain the path used by this 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?
+ * @param cc connection
+ * @return path to @a cc
*/
-void
-GCC_start_poll (struct CadetConnection *c, int fwd);
+struct CadetPeerPath *
+GCC_get_path (struct CadetConnection *cc);
/**
- * @brief Stop polling a connection for ACKs.
- *
- * Once we have enough ACKs for future traffic, polls are no longer necessary.
+ * Obtain unique ID for the connection.
*
- * @param c Connection.
- * @param fwd Should we stop the poll in the FWD direction?
+ * @param cc connection.
+ * @return unique number of the connection
*/
-void
-GCC_stop_poll (struct CadetConnection *c, int fwd);
+const struct GNUNET_CADET_ConnectionTunnelIdentifier *
+GCC_get_id (struct CadetConnection *cc);
+
/**
* Get a (static) string for a connection.
*
- * @param c Connection.
+ * @param cc Connection.
*/
const char *
-GCC_2s (const struct CadetConnection *c);
+GCC_2s (const struct CadetConnection *cc);
+
/**
- * Log all possible info about the connection state.
+ * Log connection info.
*
- * @param c Connection to debug.
+ * @param cc connection
* @param level Debug level to use.
*/
void
-GCC_debug (const struct CadetConnection *c, enum GNUNET_ErrorType level);
+GCC_debug (struct CadetConnection *cc,
+ enum GNUNET_ErrorType level);
-#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-new_core.c b/src/cadet/gnunet-service-cadet_core.c
index 3768c36a56..ae03b4f355 100644
--- a/src/cadet/gnunet-service-cadet-new_core.c
+++ b/src/cadet/gnunet-service-cadet_core.c
@@ -30,11 +30,11 @@
* - Optimization: given BROKEN messages, destroy paths (?)
*/
#include "platform.h"
-#include "gnunet-service-cadet-new_core.h"
-#include "gnunet-service-cadet-new_paths.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_connection.h"
-#include "gnunet-service-cadet-new_tunnels.h"
+#include "gnunet-service-cadet_core.h"
+#include "gnunet-service-cadet_paths.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_tunnels.h"
#include "gnunet_core_service.h"
#include "gnunet_statistics_service.h"
#include "cadet_protocol.h"
diff --git a/src/cadet/gnunet-service-cadet-new_core.h b/src/cadet/gnunet-service-cadet_core.h
index 65b0a6ba5f..65b0a6ba5f 100644
--- a/src/cadet/gnunet-service-cadet-new_core.h
+++ b/src/cadet/gnunet-service-cadet_core.h
diff --git a/src/cadet/gnunet-service-cadet_dht.c b/src/cadet/gnunet-service-cadet_dht.c
index 22673b1670..f00c0caf3b 100644
--- a/src/cadet/gnunet-service-cadet_dht.c
+++ b/src/cadet/gnunet-service-cadet_dht.c
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet.
- Copyright (C) 2013 GNUnet e.V.
+ Copyright (C) 2013, 2017 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
@@ -17,25 +17,41 @@
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
-
+/**
+ * @file cadet/gnunet-service-cadet_dht.c
+ * @brief Information we track per peer.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
#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.h"
#include "gnunet-service-cadet_dht.h"
-#include "gnunet-service-cadet_peer.h"
#include "gnunet-service-cadet_hello.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_paths.h"
-#define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__)
+/**
+ * How long do we wait before first announcing our presence to the DHT.
+ * Used to wait for our HELLO to be available. Note that we also get
+ * notifications when our HELLO is ready, so this is just the maximum
+ * we wait for the first notification.
+ */
+#define STARTUP_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500)
+/**
+ * How long do we wait after we get an updated HELLO before publishing?
+ * Allows for the HELLO to be updated again quickly, for example in
+ * case multiple addresses changed and we got a partial update.
+ */
+#define CHANGE_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)
+
+
+#define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__)
-/******************************************************************************/
-/******************************** STRUCTS **********************************/
-/******************************************************************************/
/**
* Handle for DHT searches.
@@ -47,42 +63,9 @@ struct GCD_search_handle
*/
struct GNUNET_DHT_GetHandle *dhtget;
- /**
- * Provided callback to call when a path is found.
- */
- GCD_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.
*/
@@ -94,69 +77,20 @@ static struct GNUNET_DHT_Handle *dht_handle;
static struct GNUNET_TIME_Relative id_announce_time;
/**
- * DHT replication level, see DHT API: GNUNET_DHT_get_start, GNUNET_DHT_put.
+ * 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 struct GNUNET_SCHEDULER_Task * announce_id_task;
+static struct GNUNET_SCHEDULER_Task *announce_id_task;
/**
* Delay for the next ID announce.
*/
static struct GNUNET_TIME_Relative announce_delay;
-/**
- * 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)
-{
- size_t size = get_path_length + put_path_length + 1;
- struct GNUNET_PeerIdentity peers[size];
- const struct GNUNET_PeerIdentity *peer;
- struct CadetPeerPath *p;
- unsigned int own_pos;
- int i;
-
- peers[0] = my_full_id;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " GET has %d hops.\n", get_path_length);
- for (i = 0 ; i < get_path_length; i++)
- {
- peer = &get_path[get_path_length - i - 1];
- LOG (GNUNET_ERROR_TYPE_DEBUG, " From GET: %s\n", GNUNET_i2s (peer));
- peers[i + 1] = *peer;
- }
- for (i = 0 ; i < put_path_length; i++)
- {
- peer = &put_path[put_path_length - i - 1];
- LOG (GNUNET_ERROR_TYPE_DEBUG, " From PUT: %s\n", GNUNET_i2s (peer));
- peers[i + get_path_length + 1] = *peer;
- }
- p = path_build_from_peer_ids (peers, size, myid, &own_pos);
- return p;
-}
-
/**
* Function to process paths received for a new peer addition. The recorded
@@ -176,42 +110,34 @@ path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
*/
static void
dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
- const struct GNUNET_HashCode * key,
+ 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)
+ unsigned int put_path_length,
+ enum GNUNET_BLOCK_Type type,
+ size_t size,
+ const void *data)
{
- struct GCD_search_handle *h = cls;
- struct GNUNET_HELLO_Message *hello;
- struct CadetPeerPath *p;
+ const struct GNUNET_HELLO_Message *hello = data;
struct CadetPeer *peer;
- char *s;
- p = path_build_from_dht (get_path, get_path_length,
- put_path, put_path_length);
- if (NULL == p)
+ GCPP_try_path_from_dht (get_path,
+ get_path_length,
+ put_path,
+ put_path_length);
+ if ( (size >= sizeof (struct GNUNET_HELLO_Message)) &&
+ (ntohs (hello->header.size) == size) &&
+ (size == GNUNET_HELLO_size (hello)) )
{
- GNUNET_break_op (0);
- return;
+ peer = GCP_get (&put_path[0],
+ GNUNET_YES);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Got HELLO for %s\n",
+ GCP_2s (peer));
+ GCP_set_hello (peer,
+ hello);
}
-
- s = path_2s (p);
- LOG (GNUNET_ERROR_TYPE_INFO,
- "Got path from DHT: %s\n",
- s);
- GNUNET_free_non_null (s);
-
- peer = GCP_get_short (p->peers[p->length - 1], GNUNET_YES);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Got HELLO for %s\n",
- GCP_2s (peer));
- h->callback (h->cls, p);
- path_destroy (p);
- hello = (struct GNUNET_HELLO_Message *) data;
- GCP_set_hello (peer, hello);
- GCP_try_connect (peer);
}
@@ -229,19 +155,10 @@ announce_id (void *cls)
struct GNUNET_TIME_Absolute expiration;
struct GNUNET_TIME_Relative next_put;
- announce_id_task = NULL;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Announce ID\n");
hello = GCH_get_mine ();
size = (NULL != hello) ? GNUNET_HELLO_size (hello) : 0;
- if ( (NULL == hello) || (0 == size) )
+ if (0 == size)
{
- /* Peerinfo gave us no hello yet, try again soon. */
- LOG (GNUNET_ERROR_TYPE_INFO,
- " no hello, waiting!\n");
- GNUNET_STATISTICS_update (stats,
- "# DHT announce skipped (no hello)",
- 1,
- GNUNET_NO);
expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
announce_delay);
announce_delay = GNUNET_TIME_STD_BACKOFF (announce_delay);
@@ -252,71 +169,64 @@ announce_id (void *cls)
announce_delay = GNUNET_TIME_UNIT_SECONDS;
}
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Hello %p size: %u\n",
- hello,
- size);
- if (NULL != hello)
- {
- GNUNET_STATISTICS_update (stats,
- "# DHT announce",
- 1, GNUNET_NO);
- memset (&phash,
- 0,
- sizeof (phash));
- GNUNET_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 */
- NULL, /* Continuation */
- NULL); /* Continuation closure */
- }
/* Call again in id_announce_time, unless HELLO expires first,
* but wait at least 1s. */
- next_put = GNUNET_TIME_absolute_get_remaining (expiration);
- next_put = GNUNET_TIME_relative_min (next_put,
- id_announce_time);
- next_put = GNUNET_TIME_relative_max (next_put,
- GNUNET_TIME_UNIT_SECONDS);
- announce_id_task = GNUNET_SCHEDULER_add_delayed (next_put,
- &announce_id,
- cls);
+ next_put
+ = GNUNET_TIME_absolute_get_remaining (expiration);
+ next_put
+ = GNUNET_TIME_relative_min (next_put,
+ id_announce_time);
+ next_put
+ = GNUNET_TIME_relative_max (next_put,
+ GNUNET_TIME_UNIT_SECONDS);
+ announce_id_task
+ = GNUNET_SCHEDULER_add_delayed (next_put,
+ &announce_id,
+ cls);
+ GNUNET_STATISTICS_update (stats,
+ "# DHT announce",
+ 1,
+ GNUNET_NO);
+ memset (&phash,
+ 0,
+ sizeof (phash));
+ GNUNET_memcpy (&phash,
+ &my_full_id,
+ sizeof (my_full_id));
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Announcing my HELLO (%u bytes) in the DHT\n",
+ size);
+ 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 */
+ NULL, /* Continuation */
+ NULL); /* Continuation closure */
}
+
/**
- * 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 (GCD_search_handle).
- *
- * @return #GNUNET_YES, we should continue to iterate,
+ * Function called by the HELLO subsystem whenever OUR hello
+ * changes. Re-triggers the DHT PUT immediately.
*/
-int
-stop_get (void *cls,
- uint32_t key,
- void *value)
+void
+GCD_hello_update ()
{
- struct GCD_search_handle *h = value;
-
- GCD_search_stop (h);
- return GNUNET_YES;
+ if (NULL == announce_id_task)
+ return; /* too early */
+ GNUNET_SCHEDULER_cancel (announce_id_task);
+ announce_id_task
+ = GNUNET_SCHEDULER_add_delayed (CHANGE_DELAY,
+ &announce_id,
+ NULL);
}
-/******************************************************************************/
-/******************************** API ***********************************/
-/******************************************************************************/
-
/**
* Initialize the DHT subsystem.
*
@@ -325,36 +235,40 @@ stop_get (void *cls,
void
GCD_init (const struct GNUNET_CONFIGURATION_Handle *c)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (c, "CADET",
+ 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");
+ 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",
+ 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_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);
- }
-
+ dht_handle = GNUNET_DHT_connect (c,
+ 64);
+ GNUNET_break (NULL != dht_handle);
announce_delay = GNUNET_TIME_UNIT_SECONDS;
- announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL);
- get_requests = GNUNET_CONTAINER_multihashmap32_create (32);
+ announce_id_task = GNUNET_SCHEDULER_add_delayed (STARTUP_DELAY,
+ &announce_id,
+ NULL);
}
@@ -364,10 +278,7 @@ GCD_init (const struct GNUNET_CONFIGURATION_Handle *c)
void
GCD_shutdown (void)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down DHT\n");
- GNUNET_CONTAINER_multihashmap32_iterate (get_requests, &stop_get, NULL);
- GNUNET_CONTAINER_multihashmap32_destroy (get_requests);
- if (dht_handle != NULL)
+ if (NULL != dht_handle)
{
GNUNET_DHT_disconnect (dht_handle);
dht_handle = NULL;
@@ -379,22 +290,31 @@ GCD_shutdown (void)
}
}
+
+/**
+ * Search DHT for paths to @a peeR_id
+ *
+ * @param peer_id peer to search for
+ * @return handle to abort search
+ */
struct GCD_search_handle *
-GCD_search (const struct GNUNET_PeerIdentity *peer_id,
- GCD_search_callback callback, void *cls)
+GCD_search (const struct GNUNET_PeerIdentity *peer_id)
{
struct GNUNET_HashCode phash;
struct GCD_search_handle *h;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting DHT GET for peer %s\n",
- GNUNET_i2s (peer_id));
- GNUNET_STATISTICS_update (stats, "# DHT search", 1, GNUNET_NO);
- memset (&phash, 0, sizeof (phash));
- GNUNET_memcpy (&phash, peer_id, sizeof (*peer_id));
+ GNUNET_STATISTICS_update (stats,
+ "# DHT search",
+ 1,
+ GNUNET_NO);
+ memset (&phash,
+ 0,
+ sizeof (phash));
+ GNUNET_memcpy (&phash,
+ peer_id,
+ sizeof (*peer_id));
+
h = GNUNET_new (struct GCD_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 */
@@ -405,20 +325,27 @@ GCD_search (const struct GNUNET_PeerIdentity *peer_id,
0, /* xquery bits */
&dht_get_id_handler,
h);
- GNUNET_CONTAINER_multihashmap32_put (get_requests,
- h->peer_id,
- h,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Starting DHT GET for peer %s (%p)\n",
+ GNUNET_i2s (peer_id),
+ h);
return h;
}
+/**
+ * Stop DHT search started with #GCD_search().
+ *
+ * @param h handle to search to stop
+ */
void
GCD_search_stop (struct GCD_search_handle *h)
{
- GNUNET_break (GNUNET_OK ==
- GNUNET_CONTAINER_multihashmap32_remove (get_requests,
- h->peer_id, h));
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Stopping DHT GET %p\n",
+ h);
GNUNET_DHT_get_stop (h->dhtget);
GNUNET_free (h);
}
+
+/* end of gnunet-service-cadet_dht.c */
diff --git a/src/cadet/gnunet-service-cadet_dht.h b/src/cadet/gnunet-service-cadet_dht.h
index b70dfe975f..5d7ab29a06 100644
--- a/src/cadet/gnunet-service-cadet_dht.h
+++ b/src/cadet/gnunet-service-cadet_dht.h
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet.
- Copyright (C) 2013 GNUnet e.V.
+ Copyright (C) 2013, 2017 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
@@ -22,10 +22,10 @@
* @file cadet/gnunet-service-cadet_dht.h
* @brief cadet service; dealing with DHT requests and results
* @author Bartlomiej Polot
+ * @author Christian Grothoff
*
- * All functions in this file should use the prefix GMD (Gnunet Cadet Dht)
+ * All functions in this file should use the prefix GCD (Gnunet Cadet Dht)
*/
-
#ifndef GNUNET_SERVICE_CADET_DHT_H
#define GNUNET_SERVICE_CADET_DHT_H
@@ -40,23 +40,11 @@ extern "C"
#include "platform.h"
#include "gnunet_util_lib.h"
-struct GCD_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!
+ * Handle for DHT search operation.
*/
-typedef void
-(*GCD_search_callback) (void *cls,
- const struct CadetPeerPath *path);
+struct GCD_search_handle;
-/******************************************************************************/
-/******************************** API ***********************************/
-/******************************************************************************/
/**
* Initialize the DHT subsystem.
@@ -66,6 +54,7 @@ typedef void
void
GCD_init (const struct GNUNET_CONFIGURATION_Handle *c);
+
/**
* Shut down the DHT subsystem.
*/
@@ -73,14 +62,32 @@ void
GCD_shutdown (void);
+/**
+ * Function called by the HELLO subsystem whenever OUR hello
+ * changes. Re-triggers the DHT PUT immediately.
+ */
+void
+GCD_hello_update (void);
+
+/**
+ * Search DHT for paths to @a peeR_id
+ *
+ * @param peer_id peer to search for
+ * @return handle to abort search
+ */
struct GCD_search_handle *
-GCD_search (const struct GNUNET_PeerIdentity *peer_id,
- GCD_search_callback callback, void *cls);
+GCD_search (const struct GNUNET_PeerIdentity *peer_id);
+/**
+ * Stop DHT search started with #GCD_search().
+ *
+ * @param h handle to search to stop
+ */
void
GCD_search_stop (struct GCD_search_handle *h);
+
#if 0 /* keep Emacsens' auto-indent happy */
{
#endif
@@ -88,6 +95,6 @@ GCD_search_stop (struct GCD_search_handle *h);
}
#endif
-/* ifndef GNUNET_CADET_SERVICE_LOCAL_H */
+/* ifndef GNUNET_CADET_SERVICE_DHT_H */
#endif
-/* end of gnunet-cadet-service_LOCAL.h */
+/* end of gnunet-service-cadet_dht.h */
diff --git a/src/cadet/gnunet-service-cadet_hello.c b/src/cadet/gnunet-service-cadet_hello.c
index 3c63f3551b..6d85de39f6 100644
--- a/src/cadet/gnunet-service-cadet_hello.c
+++ b/src/cadet/gnunet-service-cadet_hello.c
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet.
- Copyright (C) 2014 GNUnet e.V.
+ Copyright (C) 2014, 2017 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
@@ -17,58 +17,33 @@
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
-
+/**
+ * @file cadet/gnunet-service-cadet_hello.c
+ * @brief spread knowledge about how to contact other peers from PEERINFO
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * TODO:
+ * - is most of this necessary/helpful?
+ * - should we not simply restrict this to OUR hello?
+ */
#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.h"
+#include "gnunet-service-cadet_dht.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;
+static struct GNUNET_HELLO_Message *mine;
/**
* Handle to peerinfo service.
@@ -78,13 +53,9 @@ static struct GNUNET_PEERINFO_Handle *peerinfo;
/**
* Iterator context.
*/
-struct GNUNET_PEERINFO_NotifyContext* nc;
+static struct GNUNET_PEERINFO_NotifyContext *nc;
-/******************************************************************************/
-/******************************** STATIC ***********************************/
-/******************************************************************************/
-
/**
* Process each hello message received from peerinfo.
*
@@ -94,31 +65,37 @@ struct GNUNET_PEERINFO_NotifyContext* nc;
* @param err_msg Error message.
*/
static void
-got_hello (void *cls, const struct GNUNET_PeerIdentity *id,
+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)
+ if ( (NULL == id) ||
+ (NULL == hello) )
+ return;
+ if (0 == memcmp (id,
+ &my_full_id,
+ sizeof (struct GNUNET_PeerIdentity)))
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " hello with id %p and msg %p\n", id, hello);
+ GNUNET_free_non_null (mine);
+ mine = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (&hello->header);
+ GCD_hello_update ();
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 = GCP_get (id, GNUNET_YES);
- GCP_set_hello (peer, hello);
-
- if (GCP_get_short_id (peer) == myid)
- mine = GCP_get_hello (peer);
-}
+ 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 = GCP_get (id,
+ GNUNET_YES);
+ GCP_set_hello (peer,
+ hello);
+}
-/******************************************************************************/
-/******************************** API ***********************************/
-/******************************************************************************/
/**
* Initialize the hello subsystem.
@@ -128,10 +105,12 @@ got_hello (void *cls, const struct GNUNET_PeerIdentity *id,
void
GCH_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);
+ nc = GNUNET_PEERINFO_notify (c,
+ GNUNET_NO,
+ &got_hello,
+ NULL);
}
@@ -141,7 +120,6 @@ GCH_init (const struct GNUNET_CONFIGURATION_Handle *c)
void
GCH_shutdown ()
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down channels\n");
if (NULL != nc)
{
GNUNET_PEERINFO_notify_cancel (nc);
@@ -152,6 +130,11 @@ GCH_shutdown ()
GNUNET_PEERINFO_disconnect (peerinfo);
peerinfo = NULL;
}
+ if (NULL != mine)
+ {
+ GNUNET_free (mine);
+ mine = NULL;
+ }
}
@@ -166,35 +149,4 @@ GCH_get_mine (void)
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 *
-GCH_get (const struct GNUNET_PeerIdentity *id)
-{
- struct CadetPeer *p;
-
- p = GCP_get (id, GNUNET_NO);
- if (NULL == p)
- return NULL;
- return GCP_get_hello (p);
-}
-
-
-/**
- * Convert a hello message to a string.
- *
- * @param h Hello message.
- */
-char *
-GCH_2s (const struct GNUNET_HELLO_Message *h)
-{
- return "hello (TODO)";
-}
-
-
+/* end of gnunet-service-cadet-new_hello.c */
diff --git a/src/cadet/gnunet-service-cadet_hello.h b/src/cadet/gnunet-service-cadet_hello.h
index 34121e1e01..4291ae985d 100644
--- a/src/cadet/gnunet-service-cadet_hello.h
+++ b/src/cadet/gnunet-service-cadet_hello.h
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet.
- Copyright (C) 2014 GNUnet e.V.
+ Copyright (C) 2014, 2017 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
@@ -22,8 +22,9 @@
* @file cadet/gnunet-service-cadet_hello.h
* @brief cadet service; dealing with hello messages
* @author Bartlomiej Polot
+ * @author Christian Grothoff
*
- * All functions in this file should use the prefix GMH (Gnunet Cadet Hello)
+ * All functions in this file should use the prefix GCH (Gnunet Cadet Hello)
*/
#ifndef GNUNET_SERVICE_CADET_HELLO_H
diff --git a/src/cadet/gnunet-service-cadet_local.c b/src/cadet/gnunet-service-cadet_local.c
deleted file mode 100644
index dea6681df8..0000000000
--- a/src/cadet/gnunet-service-cadet_local.c
+++ /dev/null
@@ -1,1553 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2013 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, 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.
- */
- struct GNUNET_CADET_ClientChannelNumber next_ccn;
-
- /**
- * 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_MultiHashMap *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_MultiHashMap *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,
- const struct GNUNET_HashCode *key,
- void *value)
-{
- int res;
-
- res = GNUNET_CONTAINER_multihashmap_remove (ports, key, value);
- if (GNUNET_YES != res)
- {
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "Port %s by client %p was not registered.\n",
- GNUNET_h2s (key), value);
- }
- return GNUNET_OK;
-}
-
-
-/**
- * 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",
- GCCH_2s (ch), GML_2s (c));
-
- GCCH_handle_local_destroy (ch,
- c,
- key < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
- return GNUNET_OK;
-}
-
-
-/**
- * Unregister data and free memory for a client.
- *
- * @param c Client to destroy. No longer valid after call.
- */
-static void
-client_destroy (struct CadetClient *c)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " client destroy: %p/%u\n", c, c->id);
- 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_multihashmap_iterate (c->ports,
- &client_release_ports, c);
- GNUNET_CONTAINER_multihashmap_destroy (c->ports);
- }
-
- GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, c);
- GNUNET_STATISTICS_update (stats, "# clients", -1, GNUNET_NO);
- GNUNET_SERVER_client_set_user_context (c->handle, NULL);
- GNUNET_free (c);
-}
-
-
-/**
- * Create a client record, register data and initialize memory.
- *
- * @param client Client's handle.
- */
-static struct CadetClient *
-client_new (struct GNUNET_SERVER_Client *client)
-{
- struct CadetClient *c;
-
- GNUNET_SERVER_client_keep (client);
- GNUNET_SERVER_notification_context_add (nc, client);
-
- c = GNUNET_new (struct CadetClient);
- c->handle = client;
- c->id = next_client_id++; /* overflow not important: just for debug */
-
- c->own_channels = GNUNET_CONTAINER_multihashmap32_create (32);
- c->incoming_channels = GNUNET_CONTAINER_multihashmap32_create (32);
-
- GNUNET_SERVER_client_set_user_context (client, c);
- GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, c);
- GNUNET_STATISTICS_update (stats, "# clients", +1, GNUNET_NO);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " client created: %p/%u\n", c, c->id);
-
- return c;
-}
-
-
-/******************************************************************************/
-/******************************** 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)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client);
- if (NULL == client)
- return;
-
- (void) client_new (client);
-}
-
-
-/**
- * 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);
-
- c = GML_client_get (client);
- if (NULL != c)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "matching client found (%u, %p)\n",
- c->id, c);
- client_destroy (c);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " disconnecting client's context NULL\n");
- }
- return;
-}
-
-
-/**
- * Handler for port open requests.
- *
- * @param cls Closure.
- * @param client Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_port_open (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- struct CadetClient *c;
- struct GNUNET_CADET_PortMessage *pmsg;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "open port 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_PortMessage) != ntohs (message->size))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
-
- pmsg = (struct GNUNET_CADET_PortMessage *) message;
- if (NULL == c->ports)
- {
- c->ports = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_NO);
- }
- /* store in client's hashmap */
- if (GNUNET_OK !=
- GNUNET_CONTAINER_multihashmap_put (c->ports, &pmsg->port, c,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
- /* store in global hashmap */
- /* FIXME only allow one client to have the port open,
- * have a backup hashmap with waiting clients */
- GNUNET_CONTAINER_multihashmap_put (ports, &pmsg->port, c,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
-
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Handler for port close requests.
- *
- * @param cls Closure.
- * @param client Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_port_close (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- struct CadetClient *c;
- struct GNUNET_CADET_PortMessage *pmsg;
- int removed;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "close port 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_PortMessage) != ntohs (message->size))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
-
- pmsg = (struct GNUNET_CADET_PortMessage *) message;
- removed = GNUNET_CONTAINER_multihashmap_remove (c->ports, &pmsg->port, c);
- GNUNET_break_op (GNUNET_YES == removed);
- removed = GNUNET_CONTAINER_multihashmap_remove (ports, &pmsg->port, c);
- GNUNET_break_op (GNUNET_YES == removed);
-
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Handler for requests of new channels.
- *
- * @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_LocalChannelCreateMessage)
- != ntohs (message->size))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
-
- if (GNUNET_OK !=
- GCCH_handle_local_create (c,
- (struct GNUNET_CADET_LocalChannelCreateMessage *)
- message))
- {
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
-
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * 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)
-{
- const struct GNUNET_CADET_LocalChannelDestroyMessage *msg;
- struct CadetClient *c;
- struct CadetChannel *ch;
- struct GNUNET_CADET_ClientChannelNumber ccn;
-
- 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_LocalChannelDestroyMessage)
- != ntohs (message->size))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
-
- msg = (const struct GNUNET_CADET_LocalChannelDestroyMessage *) message;
-
- /* Retrieve tunnel */
- ccn = msg->ccn;
- ch = GML_channel_get (c, ccn);
-
- LOG (GNUNET_ERROR_TYPE_INFO, "Client %u is destroying channel %X\n",
- c->id, ccn);
-
- if (NULL == ch)
- {
- LOG (GNUNET_ERROR_TYPE_WARNING, " channel %X not found\n", ccn);
- GNUNET_STATISTICS_update (stats,
- "# client destroy messages on unknown channel",
- 1, GNUNET_NO);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
- }
-
- GCCH_handle_local_destroy (ch,
- c,
- ntohl (ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
-
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * 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)
-{
- const struct GNUNET_MessageHeader *payload;
- struct GNUNET_CADET_LocalData *msg;
- struct CadetClient *c;
- struct CadetChannel *ch;
- struct GNUNET_CADET_ClientChannelNumber ccn;
- size_t message_size;
- size_t payload_size;
- size_t payload_claimed_size;
- int fwd;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
- 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;
- }
-
- /* Sanity check for message size */
- message_size = ntohs (message->size);
- if (sizeof (struct GNUNET_CADET_LocalData)
- + sizeof (struct GNUNET_MessageHeader) > message_size
- || GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < message_size)
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
-
- /* Sanity check for payload size */
- payload_size = message_size - sizeof (struct GNUNET_CADET_LocalData);
- msg = (struct GNUNET_CADET_LocalData *) message;
- payload = (struct GNUNET_MessageHeader *) &msg[1];
- payload_claimed_size = ntohs (payload->size);
- if (sizeof (struct GNUNET_MessageHeader) > payload_claimed_size
- || GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_claimed_size
- || payload_claimed_size > payload_size)
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "client claims to send %u bytes in %u payload\n",
- payload_claimed_size, payload_size);
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
-
- ccn = msg->ccn;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " %u bytes (%u payload) by client %u\n",
- payload_size, payload_claimed_size, c->id);
-
- /* Channel exists? */
- fwd = ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
- ch = GML_channel_get (c, ccn);
- 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 != GCCH_handle_local_data (ch, c, fwd, payload, payload_size))
- {
- 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;
- struct GNUNET_CADET_ClientChannelNumber ccn;
- 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? */
- ccn = msg->ccn;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X\n",
- ntohl (ccn.channel_of_client));
- ch = GML_channel_get (c, ccn);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " -- ch %p\n", ch);
- if (NULL == ch)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Channel %X unknown.\n",
- ntohl (ccn.channel_of_client));
- 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 = ntohl (ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
-
- GCCH_handle_local_ack (ch, fwd);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * 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 (GCP_count_paths (p));
- msg.tunnel = htons (NULL != GCP_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;
-}
-
-
-/**
- * Iterator over all peers to dump info for each peer.
- *
- * @param cls Closure (unused).
- * @param peer Peer ID (tunnel remote peer).
- * @param value Peer info.
- *
- * @return #GNUNET_YES, to keep iterating.
- */
-static int
-show_peer_iterator (void *cls,
- const struct GNUNET_PeerIdentity * peer,
- void *value)
-{
- struct CadetPeer *p = value;
- struct CadetTunnel *t;
-
- t = GCP_get_tunnel (p);
- if (NULL != t)
- GCT_debug (t, GNUNET_ERROR_TYPE_ERROR);
-
- LOG (GNUNET_ERROR_TYPE_ERROR, "\n");
-
- return GNUNET_YES;
-}
-
-
-/**
- * Iterator over all paths of a peer to build an InfoPeer message.
- *
- * Message contains blocks of peers, first not included.
- *
- * @param cls Closure (message to build).
- * @param peer Peer this path is towards.
- * @param path Path itself
- * @return #GNUNET_YES if should keep iterating.
- * #GNUNET_NO otherwise.
- */
-static int
-path_info_iterator (void *cls,
- struct CadetPeer *peer,
- struct CadetPeerPath *path)
-{
- struct GNUNET_CADET_LocalInfoPeer *resp = cls;
- struct GNUNET_PeerIdentity *id;
- uint16_t msg_size;
- uint16_t path_size;
- unsigned int i;
-
- msg_size = ntohs (resp->header.size);
- path_size = sizeof (struct GNUNET_PeerIdentity) * (path->length - 1);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Info Path %u\n", path->length);
- if (msg_size + path_size > UINT16_MAX)
- {
- LOG (GNUNET_ERROR_TYPE_WARNING, "path too long for info message\n");
- return GNUNET_NO;
- }
-
- i = msg_size - sizeof (struct GNUNET_CADET_LocalInfoPeer);
- i = i / sizeof (struct GNUNET_PeerIdentity);
-
- /* Set id to the address of the first free peer slot. */
- id = (struct GNUNET_PeerIdentity *) &resp[1];
- id = &id[i];
-
- /* Don't copy first peers.
- * First peer is always the local one.
- * Last peer is always the destination (leave as 0, EOL).
- */
- for (i = 0; i < path->length - 1; i++)
- {
- GNUNET_PEER_resolve (path->peers[i + 1], &id[i]);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " %s\n", GNUNET_i2s (&id[i]));
- }
-
- resp->header.size = htons (msg_size + path_size);
-
- 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);
-
- GCP_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);
-}
-
-
-/**
- * Handler for client's SHOW_PEER request.
- *
- * @param cls Closure (unused).
- * @param client Identification of the client.
- * @param message The actual message.
- */
-void
-handle_show_peer (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- const struct GNUNET_CADET_LocalInfo *msg;
- struct GNUNET_CADET_LocalInfoPeer *resp;
- struct CadetPeer *p;
- struct CadetClient *c;
- unsigned char cbuf[64 * 1024];
-
- /* 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;
- resp = (struct GNUNET_CADET_LocalInfoPeer *) cbuf;
- LOG (GNUNET_ERROR_TYPE_INFO,
- "Received peer info request from client %u for peer %s\n",
- c->id, GNUNET_i2s_full (&msg->peer));
-
- resp->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
- resp->header.size = htons (sizeof (struct GNUNET_CADET_LocalInfoPeer));
- resp->destination = msg->peer;
- p = GCP_get (&msg->peer, GNUNET_NO);
- if (NULL == p)
- {
- /* We don't know the peer */
-
- LOG (GNUNET_ERROR_TYPE_INFO, "Peer %s unknown\n",
- GNUNET_i2s_full (&msg->peer));
- resp->paths = htons (0);
- resp->tunnel = htons (NULL != GCP_get_tunnel (p));
-
- GNUNET_SERVER_notification_context_unicast (nc, client,
- &resp->header,
- GNUNET_NO);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
- }
-
- resp->paths = htons (GCP_count_paths (p));
- resp->tunnel = htons (NULL != GCP_get_tunnel (p));
- GCP_iterate_paths (p, &path_info_iterator, resp);
-
- GNUNET_SERVER_notification_context_unicast (nc, c->handle,
- &resp->header, GNUNET_NO);
-
- LOG (GNUNET_ERROR_TYPE_INFO, "Show peer 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 CadetTunnel *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 (GCT_count_channels (t));
- msg.connections = htonl (GCT_count_any_connections (t));
- msg.cstate = htons ((uint16_t) GCT_get_cstate (t));
- msg.estate = htons ((uint16_t) GCT_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);
-
- GCT_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_ConnectionTunnelIdentifier *h;
-
- h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
- h[msg->connections] = *(GCC_get_id (c));
- msg->connections++;
-}
-
-static void
-iter_channel (void *cls, struct CadetChannel *ch)
-{
- struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
- struct GNUNET_CADET_ConnectionTunnelIdentifier *h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
- struct GNUNET_CADET_ChannelTunnelNumber *chn = (struct GNUNET_CADET_ChannelTunnelNumber *) &h[msg->connections];
-
- chn[msg->channels] = GCCH_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 CadetTunnel *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_DEBUG,
- "Received tunnel info request from client %u for tunnel %s\n",
- c->id, GNUNET_i2s_full(&msg->peer));
-
- t = GCP_get_tunnel (GCP_get (&msg->peer, GNUNET_NO));
- 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 = GCT_count_channels (t);
- c_n = GCT_count_any_connections (t);
-
- size = sizeof (struct GNUNET_CADET_LocalInfoTunnel);
- size += c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier);
- size += ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber);
-
- resp = GNUNET_malloc (size);
- resp->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
- resp->header.size = htons (size);
- resp->destination = msg->peer;
- /* Do not interleave with iterators, iter_channel needs conn in HBO */
- GCT_iterate_connections (t, &iter_connection, resp);
- GCT_iterate_channels (t, &iter_channel, resp);
- resp->connections = htonl (resp->connections);
- resp->channels = htonl (resp->channels);
- /* Do not interleave end */
- resp->cstate = htons (GCT_get_cstate (t));
- resp->estate = htons (GCT_get_estate (t));
- GNUNET_SERVER_notification_context_unicast (nc, c->handle,
- &resp->header, GNUNET_NO);
- GNUNET_free (resp);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "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);
-}
-
-
-/**
- * Handler for client's INFO_DUMP request.
- *
- * @param cls Closure (unused).
- * @param client Identification of the client.
- * @param message The actual message.
- */
-void
-handle_info_dump (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- struct CadetClient *c;
-
- /* 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_INFO, "Received dump info request from client %u\n",
- c->id);
- LOG (GNUNET_ERROR_TYPE_ERROR,
- "*************************** DUMP START ***************************\n");
-
- for (c = clients_head; NULL != c; c = c->next)
- {
- LOG (GNUNET_ERROR_TYPE_ERROR, "Client %u (%p), handle: %p\n",
- c->id, c, c->handle);
- if (NULL != c->ports)
- LOG (GNUNET_ERROR_TYPE_ERROR, "\t%3u ports registered\n",
- GNUNET_CONTAINER_multihashmap_size (c->ports));
- else
- LOG (GNUNET_ERROR_TYPE_ERROR, "\t no ports registered\n");
- LOG (GNUNET_ERROR_TYPE_ERROR, "\t%3u own channles\n",
- GNUNET_CONTAINER_multihashmap32_size (c->own_channels));
- LOG (GNUNET_ERROR_TYPE_ERROR, "\t%3u incoming channles\n",
- GNUNET_CONTAINER_multihashmap32_size (c->incoming_channels));
- }
- LOG (GNUNET_ERROR_TYPE_ERROR, "***************************\n");
- GCP_iterate_all (&show_peer_iterator, NULL);
-
- LOG (GNUNET_ERROR_TYPE_ERROR,
- "**************************** DUMP END ****************************\n");
-
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Functions to handle messages from clients
- */
-static struct GNUNET_SERVER_MessageHandler client_handlers[] = {
- {&handle_port_open, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN,
- sizeof (struct GNUNET_CADET_PortMessage)},
- {&handle_port_close, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE,
- sizeof (struct GNUNET_CADET_PortMessage)},
- {&handle_channel_create, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE,
- sizeof (struct GNUNET_CADET_LocalChannelCreateMessage)},
- {&handle_channel_destroy, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY,
- sizeof (struct GNUNET_CADET_LocalChannelDestroyMessage)},
- {&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_show_peer, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
- sizeof (struct GNUNET_CADET_LocalInfo)},
- {&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)},
- {&handle_info_dump, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP,
- sizeof (struct GNUNET_MessageHeader)},
- {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_multihashmap_create (16, GNUNET_NO);
-}
-
-
-/**
- * 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)
-{
- struct CadetClient *c;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down local\n");
-
- for (c = clients_head; NULL != clients_head; c = clients_head)
- client_destroy (c);
-
- if (nc != NULL)
- {
- GNUNET_SERVER_notification_context_destroy (nc);
- nc = NULL;
- }
-
-}
-
-
-/**
- * Get a channel from a client.
- *
- * @param c Client to check.
- * @param ccn Channel ID, must be local (> 0x800...).
- *
- * @return non-NULL if channel exists in the clients lists
- */
-struct CadetChannel *
-GML_channel_get (struct CadetClient *c,
- struct GNUNET_CADET_ClientChannelNumber ccn)
-{
- struct GNUNET_CONTAINER_MultiHashMap32 *map;
-
- if (ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
- map = c->own_channels;
- else
- map = c->incoming_channels;
-
- if (NULL == map)
- {
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Client %s does no t have a valid map for CCN %X\n",
- GML_2s (c), ccn);
- return NULL;
- }
- return GNUNET_CONTAINER_multihashmap32_get (map,
- ccn.channel_of_client);
-}
-
-
-/**
- * Add a channel to a client
- *
- * @param client Client.
- * @param ccn Channel ID.
- * @param ch Channel.
- */
-void
-GML_channel_add (struct CadetClient *client,
- struct GNUNET_CADET_ClientChannelNumber ccn,
- struct CadetChannel *ch)
-{
- if (ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
- GNUNET_CONTAINER_multihashmap32_put (client->own_channels,
- ccn.channel_of_client,
- ch,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
- else
- GNUNET_CONTAINER_multihashmap32_put (client->incoming_channels,
- ccn.channel_of_client,
- ch,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
-}
-
-
-/**
- * Remove a channel from a client.
- *
- * @param client Client.
- * @param ccn Channel ID.
- * @param ch Channel.
- */
-void
-GML_channel_remove (struct CadetClient *client,
- struct GNUNET_CADET_ClientChannelNumber ccn,
- struct CadetChannel *ch)
-{
- if (ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
- GNUNET_CONTAINER_multihashmap32_remove (client->own_channels,
- ccn.channel_of_client,
- ch);
- else
- GNUNET_CONTAINER_multihashmap32_remove (client->incoming_channels,
- ccn.channel_of_client,
- ch);
-}
-
-
-/**
- * Get the tunnel's next free local channel ID.
- *
- * @param c Client.
- *
- * @return LID of a channel free to use.
- */
-struct GNUNET_CADET_ClientChannelNumber
-GML_get_next_ccn (struct CadetClient *c)
-{
- struct GNUNET_CADET_ClientChannelNumber ccn;
-
- while (NULL != GML_channel_get (c,
- c->next_ccn))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Channel %u exists...\n",
- c->next_ccn);
- c->next_ccn.channel_of_client
- = htonl (1 + (ntohl (c->next_ccn.channel_of_client)));
- if (ntohl (c->next_ccn.channel_of_client) >=
- GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
- c->next_ccn.channel_of_client = htonl (0);
- }
- ccn = c->next_ccn;
- c->next_ccn.channel_of_client
- = htonl (1 + (ntohl (c->next_ccn.channel_of_client)));
-
- return ccn;
-}
-
-
-/**
- * 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)
-{
- if (NULL == client)
- return NULL;
- 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 (const struct GNUNET_HashCode *port)
-{
- return GNUNET_CONTAINER_multihashmap_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,
- struct GNUNET_CADET_ClientChannelNumber id)
-{
- int res;
-
- if (ntohl (id.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
- {
- res = GNUNET_CONTAINER_multihashmap32_remove (c->own_channels,
- id.channel_of_client,
- ch);
- if (GNUNET_YES != res)
- LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_tunnel root KO\n");
- }
- else
- {
- res = GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels,
- id.channel_of_client,
- ch);
- if (GNUNET_YES != res)
- LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_channel dest KO\n");
- }
-}
-
-/**
- * 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 ccn Channel ID to use
- */
-void
-GML_send_ack (struct CadetClient *c,
- struct GNUNET_CADET_ClientChannelNumber ccn)
-{
- struct GNUNET_CADET_LocalAck msg;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "send local %s ack on %X towards %p\n",
- ntohl (ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI
- ? "FWD" : "BCK",
- ntohl (ccn.channel_of_client),
- c);
-
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
- msg.ccn = ccn;
- 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 ccn 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,
- struct GNUNET_CADET_ClientChannelNumber ccn,
- const struct GNUNET_HashCode *port,
- uint32_t opt,
- const struct GNUNET_PeerIdentity *peer)
-{
- struct GNUNET_CADET_LocalChannelCreateMessage msg;
-
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
- msg.ccn = ccn;
- msg.port = *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 ccn Channel ID to use
- */
-void
-GML_send_channel_nack (struct CadetClient *c,
- struct GNUNET_CADET_ClientChannelNumber ccn)
-{
- struct GNUNET_CADET_LocalAck msg;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "send local nack on %X towards %p\n",
- ntohl (ccn.channel_of_client),
- c);
-
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED);
- msg.ccn = ccn;
- 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 ccn ID of the channel that is destroyed.
- */
-void
-GML_send_channel_destroy (struct CadetClient *c,
- struct GNUNET_CADET_ClientChannelNumber ccn)
-{
- struct GNUNET_CADET_LocalChannelDestroyMessage 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_LOCAL_CHANNEL_DESTROY);
- msg.ccn = ccn;
- 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 ccn Channel ID to use (c can be both owner and client).
- */
-void
-GML_send_data (struct CadetClient *c,
- const struct GNUNET_CADET_ChannelAppDataMessage *msg,
- struct GNUNET_CADET_ClientChannelNumber ccn)
-{
- struct GNUNET_CADET_LocalData *copy;
- uint16_t size = ntohs (msg->header.size) - sizeof (struct GNUNET_CADET_ChannelAppDataMessage);
- 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;
- GNUNET_memcpy (&copy[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->ccn = ccn;
- GNUNET_SERVER_notification_context_unicast (nc, c->handle,
- &copy->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
deleted file mode 100644
index 113c2f489c..0000000000
--- a/src/cadet/gnunet-service-cadet_local.h
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2013 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, 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 ccn Channel ID, must be local (> 0x800...).
- *
- * @return non-NULL if channel exists in the clients lists
- */
-struct CadetChannel *
-GML_channel_get (struct CadetClient *c,
- struct GNUNET_CADET_ClientChannelNumber ccn);
-
-/**
- * Add a channel to a client
- *
- * @param client Client.
- * @param ccn Channel ID.
- * @param ch Channel.
- */
-void
-GML_channel_add (struct CadetClient *client,
- struct GNUNET_CADET_ClientChannelNumber ccn,
- struct CadetChannel *ch);
-
-/**
- * Remove a channel from a client
- *
- * @param client Client.
- * @param ccn Channel ID.
- * @param ch Channel.
- */
-void
-GML_channel_remove (struct CadetClient *client,
- struct GNUNET_CADET_ClientChannelNumber ccn,
- struct CadetChannel *ch);
-
-/**
- * Get the tunnel's next free local channel ID.
- *
- * @param c Client.
- *
- * @return LID of a channel free to use.
- */
-struct GNUNET_CADET_ClientChannelNumber
-GML_get_next_ccn (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 (const struct GNUNET_HashCode *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,
- struct GNUNET_CADET_ClientChannelNumber 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,
- struct GNUNET_CADET_ClientChannelNumber 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,
- struct GNUNET_CADET_ClientChannelNumber id,
- const struct GNUNET_HashCode *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,
- struct GNUNET_CADET_ClientChannelNumber 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,
- struct GNUNET_CADET_ClientChannelNumber 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_ChannelAppDataMessage *msg,
- struct GNUNET_CADET_ClientChannelNumber 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-new_paths.c b/src/cadet/gnunet-service-cadet_paths.c
index c6121a1336..13752643c3 100644
--- a/src/cadet/gnunet-service-cadet-new_paths.c
+++ b/src/cadet/gnunet-service-cadet_paths.c
@@ -18,16 +18,16 @@
Boston, MA 02110-1301, USA.
*/
/**
- * @file cadet/gnunet-service-cadet-new_paths.c
+ * @file cadet/gnunet-service-cadet_paths.c
* @brief Information we track per path.
* @author Bartlomiej Polot
* @author Christian Grothoff
*/
#include "platform.h"
-#include "gnunet-service-cadet-new_connection.h"
-#include "gnunet-service-cadet-new_tunnels.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_paths.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_tunnels.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_paths.h"
#define LOG(level, ...) GNUNET_log_from(level,"cadet-pat",__VA_ARGS__)
diff --git a/src/cadet/gnunet-service-cadet-new_paths.h b/src/cadet/gnunet-service-cadet_paths.h
index 7310d75e64..6b7bef640b 100644
--- a/src/cadet/gnunet-service-cadet-new_paths.h
+++ b/src/cadet/gnunet-service-cadet_paths.h
@@ -29,7 +29,7 @@
#define GNUNET_SERVICE_CADET_PATHS_H
#include "gnunet_util_lib.h"
-#include "gnunet-service-cadet-new.h"
+#include "gnunet-service-cadet.h"
/**
* Create a peer path based on the result of a DHT lookup. If we
diff --git a/src/cadet/gnunet-service-cadet_peer.c b/src/cadet/gnunet-service-cadet_peer.c
index fa3f2be806..71c7c67d0c 100644
--- a/src/cadet/gnunet-service-cadet_peer.c
+++ b/src/cadet/gnunet-service-cadet_peer.c
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet.
- Copyright (C) 2013, 2015 GNUnet e.V.
+ Copyright (C) 2001-2017 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
@@ -17,2193 +17,1461 @@
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
+
/**
* @file cadet/gnunet-service-cadet_peer.c
- * @brief GNUnet CADET service connection handling
+ * @brief Information we track per peer.
* @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * TODO:
+ * - optimize stopping/restarting DHT search to situations
+ * where we actually need it (i.e. not if we have a direct connection,
+ * or if we already have plenty of good short ones, or maybe even
+ * to take a break if we have some connections and have searched a lot (?))
*/
#include "platform.h"
#include "gnunet_util_lib.h"
+#include "gnunet_hello_lib.h"
#include "gnunet_signatures.h"
#include "gnunet_transport_service.h"
#include "gnunet_ats_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"
+#include "gnunet-service-cadet_dht.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_paths.h"
+#include "gnunet-service-cadet_tunnels.h"
-#define LOG(level, ...) GNUNET_log_from (level,"cadet-p2p",__VA_ARGS__)
-#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-p2p",__VA_ARGS__)
+#define LOG(level, ...) GNUNET_log_from(level,"cadet-per",__VA_ARGS__)
-/******************************************************************************/
-/******************************** STRUCTS **********************************/
-/******************************************************************************/
/**
- * Information about a queued message on the peer level.
+ * How long do we wait until tearing down an idle peer?
*/
-struct CadetPeerQueue {
-
- struct CadetPeerQueue *next;
- struct CadetPeerQueue *prev;
-
- /**
- * Envelope to cancel message before MQ sends it.
- */
- struct GNUNET_MQ_Envelope *env;
-
- /**
- * Peer (neighbor) this message is being sent to.
- */
- struct CadetPeer *peer;
-
- /**
- * Continuation to call to notify higher layers about message sent.
- */
- GCP_sent cont;
-
- /**
- * Closure for @a cont.
- */
- void *cont_cls;
-
- /**
- * Task to asynchronously run the drop continuation.
- */
- struct GNUNET_SCHEDULER_Task *drop_task;
-
- /**
- * Time when message was queued for sending.
- */
- struct GNUNET_TIME_Absolute queue_timestamp;
-
- /**
- * #GNUNET_YES if message was management traffic (POLL, ACK, ...).
- */
- int management_traffic;
-
- /**
- * Message type.
- */
- uint16_t type;
-
- /**
- * Message size.
- */
- uint16_t size;
-
- /**
- * Type of the message's payload, if it was encrypted data.
- */
- uint16_t payload_type;
-
- /**
- * ID of the payload (PID, ACK #, ...).
- */
- struct CadetEncryptedMessageIdentifier payload_id;
-
- /**
- * Connection this message was sent on.
- */
- struct CadetConnection *c;
-
- /**
- * Direction in @a c this message was send on (#GNUNET_YES = FWD).
- */
- int c_fwd;
-};
-
+#define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
/**
- * Struct containing all information regarding a given peer
+ * How long do we keep paths around if we no longer care about the peer?
*/
-struct CadetPeer
-{
- /**
- * ID of the peer
- */
- GNUNET_PEER_Id id;
-
- struct CadetPeerQueue *q_head;
- struct CadetPeerQueue *q_tail;
-
- /**
- * 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 GCD_search_handle *search_h;
-
- /**
- * Handle to stop the DHT search for paths to this peer
- */
- struct GNUNET_SCHEDULER_Task *search_delayed;
-
- /**
- * Tunnel to this peer, if any.
- */
- struct CadetTunnel *tunnel;
-
- /**
- * Connections that go through this peer; indexed by tid.
- */
- struct GNUNET_CONTAINER_MultiShortmap *connections;
-
- /**
- * Handle for core transmissions.
- */
- struct GNUNET_MQ_Handle *core_mq;
-
- /**
- * How many messages are in the queue to this peer.
- */
- unsigned int queue_n;
-
- /**
- * Hello message.
- */
- struct GNUNET_HELLO_Message* hello;
-
- /**
- * Handle to us offering the HELLO to the transport.
- */
- struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
-
- /**
- * Handle to our ATS request asking ATS to suggest an address
- * to TRANSPORT for this peer (to establish a direct link).
- */
- struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
+#define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
-};
-
-
-/******************************************************************************/
-/******************************* 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, values of type `struct CadetPeer`.
+ * Data structure used to track whom we have to notify about changes
+ * to our message queue.
*/
-static struct GNUNET_CONTAINER_MultiPeerMap *peers;
-
-/**
- * How many peers do we want to remember?
- */
-static unsigned long long max_peers;
+struct GCP_MessageQueueManager
+{
-/**
- * Percentage of messages that will be dropped (for test purposes only).
- */
-static unsigned long long drop_percent;
+ /**
+ * Kept in a DLL.
+ */
+ struct GCP_MessageQueueManager *next;
-/**
- * Handle to communicate with CORE.
- */
-static struct GNUNET_CORE_Handle *core_handle;
+ /**
+ * Kept in a DLL.
+ */
+ struct GCP_MessageQueueManager *prev;
-/**
- * Our configuration;
- */
-static const struct GNUNET_CONFIGURATION_Handle *cfg;
+ /**
+ * Function to call with updated message queue object.
+ */
+ GCP_MessageQueueNotificationCallback cb;
-/**
- * Handle to communicate with ATS.
- */
-static struct GNUNET_ATS_ConnectivityHandle *ats_ch;
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
-/**
- * Shutdown falg.
- */
-static int in_shutdown;
+ /**
+ * The peer this is for.
+ */
+ struct CadetPeer *cp;
+ /**
+ * Envelope this manager would like to transmit once it is its turn.
+ */
+ struct GNUNET_MQ_Envelope *env;
-/******************************************************************************/
-/***************************** CORE HELPERS *********************************/
-/******************************************************************************/
+};
/**
- * Iterator to notify all connections of a broken link. Mark connections
- * to destroy after all traffic has been sent.
- *
- * @param cls Closure (disconnected peer).
- * @param key Current key code (peer id).
- * @param value Value in the hash map (connection).
- *
- * @return #GNUNET_YES to continue to iterate.
+ * Struct containing all information regarding a given peer
*/
-static int
-notify_broken (void *cls,
- const struct GNUNET_ShortHashCode *key,
- void *value)
+struct CadetPeer
{
- struct CadetPeer *peer = cls;
- struct CadetConnection *c = value;
+ /**
+ * ID of the peer
+ */
+ struct GNUNET_PeerIdentity pid;
+
+ /**
+ * Last time we heard from this peer (currently not used!)
+ */
+ struct GNUNET_TIME_Absolute last_contactXXX;
+
+ /**
+ * Array of DLLs of paths traversing the peer, organized by the
+ * offset of the peer on the larger path.
+ */
+ struct CadetPeerPathEntry **path_heads;
+
+ /**
+ * Array of DLL of paths traversing the peer, organized by the
+ * offset of the peer on the larger path.
+ */
+ struct CadetPeerPathEntry **path_tails;
+
+ /**
+ * Notifications to call when @e core_mq changes.
+ */
+ struct GCP_MessageQueueManager *mqm_head;
+
+ /**
+ * Notifications to call when @e core_mq changes.
+ */
+ struct GCP_MessageQueueManager *mqm_tail;
+
+ /**
+ * Pointer to first "ready" entry in @e mqm_head.
+ */
+ struct GCP_MessageQueueManager *mqm_ready_ptr;
+
+ /**
+ * MIN-heap of paths owned by this peer (they also end at this
+ * peer). Ordered by desirability.
+ */
+ struct GNUNET_CONTAINER_Heap *path_heap;
+
+ /**
+ * Handle to stop the DHT search for paths to this peer
+ */
+ struct GCD_search_handle *search_h;
+
+ /**
+ * Task to clean up @e path_heap asynchronously.
+ */
+ struct GNUNET_SCHEDULER_Task *heap_cleanup_task;
+
+ /**
+ * Task to destroy this entry.
+ */
+ struct GNUNET_SCHEDULER_Task *destroy_task;
+
+ /**
+ * Tunnel to this peer, if any.
+ */
+ struct CadetTunnel *t;
+
+ /**
+ * Connections that go through this peer; indexed by tid.
+ */
+ struct GNUNET_CONTAINER_MultiShortmap *connections;
+
+ /**
+ * Handle for core transmissions.
+ */
+ struct GNUNET_MQ_Handle *core_mq;
+
+ /**
+ * Hello message of the peer.
+ */
+ struct GNUNET_HELLO_Message *hello;
+
+ /**
+ * Handle to us offering the HELLO to the transport.
+ */
+ struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
+
+ /**
+ * Handle to our ATS request asking ATS to suggest an address
+ * to TRANSPORT for this peer (to establish a direct link).
+ */
+ struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
+
+ /**
+ * How many messages are in the queue to this peer.
+ */
+ unsigned int queue_n;
+
+ /**
+ * How many paths do we have to this peer (in all @e path_heads DLLs combined).
+ */
+ unsigned int num_paths;
+
+ /**
+ * Sum over all of the offsets of all of the paths in the @a path_heads DLLs.
+ * Used to speed-up @GCP_get_desirability_of_path() calculation.
+ */
+ unsigned int off_sum;
+
+ /**
+ * Number of message queue managers of this peer that have a message in waiting.
+ *
+ * Used to quickly see if we need to bother scanning the @e msm_head DLL.
+ * TODO: could be replaced by another DLL that would then allow us to avoid
+ * the O(n)-scan of the DLL for ready entries!
+ */
+ unsigned int mqm_ready_counter;
+
+ /**
+ * Current length of the @e path_heads and @path_tails arrays.
+ * The arrays should be grown as needed.
+ */
+ unsigned int path_dll_length;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Notifying %s due to %s disconnect\n",
- GCC_2s (c), GCP_2s (peer));
- GCC_neighbor_disconnected (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;
-}
-
-/**
- * Call the continuation after a message has been sent or dropped.
- *
- * This funcion removes the message from the queue.
+ * Get the static string for a peer ID.
*
- * @param q Queue handle.
- * @param sent #GNUNET_YES if was sent to CORE, #GNUNET_NO if dropped.
+ * @param cp Peer.
+ * @return Static string for it's ID.
*/
-static void
-call_peer_cont (struct CadetPeerQueue *q, int sent);
+const char *
+GCP_2s (const struct CadetPeer *cp)
+{
+ static char buf[32];
+
+ GNUNET_snprintf (buf,
+ sizeof (buf),
+ "P(%s)",
+ GNUNET_i2s (&cp->pid));
+ return buf;
+}
+
+
+/**
+ * Calculate how desirable a path is for @a cp if @a cp
+ * is at offset @a off.
+ *
+ * The 'desirability_table.c' program can be used to compute a list of
+ * sample outputs for different scenarios. Basically, we score paths
+ * lower if there are many alternatives, and higher if they are
+ * shorter than average, and very high if they are much shorter than
+ * average and without many alternatives.
+ *
+ * @param cp a peer reachable via a path
+ * @param off offset of @a cp in the path
+ * @return score how useful a path is to reach @a cp,
+ * positive scores mean path is more desirable
+ */
+double
+GCP_get_desirability_of_path (struct CadetPeer *cp,
+ unsigned int off)
+{
+ unsigned int num_alts = cp->num_paths;
+ unsigned int off_sum;
+ double avg_sum;
+ double path_delta;
+ double weight_alts;
+
+ GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */
+ GNUNET_assert (0 != cp->path_dll_length);
+
+ /* We maintain 'off_sum' in 'peer' and thereby
+ avoid the SLOW recalculation each time. Kept here
+ just to document what is going on. */
+#if SLOW
+ off_sum = 0;
+ for (unsigned int j=0;j<cp->path_dll_length;j++)
+ for (struct CadetPeerPathEntry *pe = cp->path_heads[j];
+ NULL != pe;
+ pe = pe->next)
+ off_sum += j;
+ GNUNET_assert (off_sum == cp->off_sum);
+#else
+ off_sum = cp->off_sum;
+#endif
+ avg_sum = off_sum * 1.0 / cp->path_dll_length;
+ path_delta = off - avg_sum;
+ /* path_delta positiv: path off of peer above average (bad path for peer),
+ path_delta negativ: path off of peer below average (good path for peer) */
+ if (path_delta <= - 1.0)
+ weight_alts = - num_alts / path_delta; /* discount alternative paths */
+ else if (path_delta >= 1.0)
+ weight_alts = num_alts * path_delta; /* overcount alternative paths */
+ else
+ weight_alts = num_alts; /* count alternative paths normally */
-/******************************************************************************/
-/***************************** CORE CALLBACKS *********************************/
-/******************************************************************************/
+ /* off+1: long paths are generally harder to find and thus count
+ a bit more as they get longer. However, above-average paths
+ still need to count less, hence the squaring of that factor. */
+ return (off + 1.0) / (weight_alts * weight_alts);
+}
/**
- * Method called whenever a given peer connects.
+ * This peer is no longer be needed, clean it up now.
*
- * @param cls Core closure (unused).
- * @param peer Peer identity this notification is about
- * @param mq Message Queue to this peer.
- *
- * @return Internal closure for handlers (CadetPeer struct).
+ * @param cls peer to clean up
*/
-static void *
-core_connect_handler (void *cls,
- const struct GNUNET_PeerIdentity *peer,
- struct GNUNET_MQ_Handle *mq)
-{
- struct CadetPeer *neighbor;
- struct CadetPeerPath *path;
- char own_id[16];
-
- GCC_check_connections ();
- GNUNET_snprintf (own_id,
- sizeof (own_id),
- "%s",
- GNUNET_i2s (&my_full_id));
-
- /* Save a path to the neighbor */
- neighbor = GCP_get (peer, GNUNET_YES);
- if (myid == neighbor->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] = neighbor->id;
- GNUNET_PEER_change_rc (neighbor->id, 1);
- GNUNET_assert (NULL == neighbor->core_mq);
- neighbor->core_mq = mq;
- }
- path->peers[0] = myid;
- GNUNET_PEER_change_rc (myid, 1);
- GCP_add_path (neighbor, path, GNUNET_YES);
-
- /* Create the connections hashmap */
- GNUNET_assert (NULL == neighbor->connections);
- neighbor->connections = GNUNET_CONTAINER_multishortmap_create (16,
- GNUNET_YES);
- GNUNET_STATISTICS_update (stats,
- "# peers",
- 1,
- GNUNET_NO);
-
- if ( (NULL != GCP_get_tunnel (neighbor)) &&
- (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, peer)) )
- {
- GCP_connect (neighbor);
- }
- GCC_check_connections ();
+static void
+destroy_peer (void *cls)
+{
+ struct CadetPeer *cp = cls;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Destroying state about peer %s\n",
+ GCP_2s (cp));
+ cp->destroy_task = NULL;
+ GNUNET_assert (NULL == cp->t);
+ GNUNET_assert (NULL == cp->core_mq);
+ GNUNET_assert (0 == cp->num_paths);
+ for (unsigned int i=0;i<cp->path_dll_length;i++)
+ GNUNET_assert (NULL == cp->path_heads[i]);
+ GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multipeermap_remove (peers,
+ &cp->pid,
+ cp));
+ GNUNET_free_non_null (cp->path_heads);
+ GNUNET_free_non_null (cp->path_tails);
+ cp->path_dll_length = 0;
+ if (NULL != cp->search_h)
+ {
+ GCD_search_stop (cp->search_h);
+ cp->search_h = NULL;
+ }
+ /* FIXME: clean up search_delayedXXX! */
- return neighbor;
+ if (NULL != cp->hello_offer)
+ {
+ GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
+ cp->hello_offer = NULL;
+ }
+ if (NULL != cp->connectivity_suggestion)
+ {
+ GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
+ cp->connectivity_suggestion = NULL;
+ }
+ GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
+ if (NULL != cp->path_heap)
+ {
+ GNUNET_CONTAINER_heap_destroy (cp->path_heap);
+ cp->path_heap = NULL;
+ }
+ if (NULL != cp->heap_cleanup_task)
+ {
+ GNUNET_SCHEDULER_cancel (cp->heap_cleanup_task);
+ cp->heap_cleanup_task = NULL;
+ }
+ GNUNET_free_non_null (cp->hello);
+ /* Peer should not be freed if paths exist; if there are no paths,
+ there ought to be no connections, and without connections, no
+ notifications. Thus we can assert that mqm_head is empty at this
+ point. */
+ GNUNET_assert (NULL == cp->mqm_head);
+ GNUNET_assert (NULL == cp->mqm_ready_ptr);
+ GNUNET_free (cp);
}
/**
- * Method called whenever a peer disconnects.
+ * This peer is now on more "active" duty, activate processes related to it.
*
- * @param cls Core closure (unused).
- * @param peer Peer identity this notification is about.
- * @param internal_cls Internal closure (CadetPeer struct).
+ * @param cp the more-active peer
*/
static void
-core_disconnect_handler (void *cls,
- const struct GNUNET_PeerIdentity *peer,
- void *internal_cls)
+consider_peer_activate (struct CadetPeer *cp)
{
- struct CadetPeer *p = internal_cls;
- struct CadetPeerPath *direct_path;
- char own_id[16];
-
- GCC_check_connections ();
- strncpy (own_id, GNUNET_i2s (&my_full_id), 16);
- own_id[15] = '\0';
- if (myid == p->id)
- {
- LOG (GNUNET_ERROR_TYPE_INFO,
- "DISCONNECTED %s (self)\n",
- own_id);
- }
- else
+ uint32_t strength;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Updating peer %s activation state (%u connections)%s%s\n",
+ GCP_2s (cp),
+ GNUNET_CONTAINER_multishortmap_size (cp->connections),
+ (NULL == cp->t) ? "" : " with tunnel",
+ (NULL == cp->core_mq) ? "" : " with CORE link");
+ if (NULL != cp->destroy_task)
+ {
+ /* It's active, do not destory! */
+ GNUNET_SCHEDULER_cancel (cp->destroy_task);
+ cp->destroy_task = NULL;
+ }
+ if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
+ (NULL == cp->t) )
+ {
+ /* We're just on a path or directly connected; don't bother too much */
+ if (NULL != cp->connectivity_suggestion)
{
- LOG (GNUNET_ERROR_TYPE_INFO,
- "DISCONNECTED %s <= %s\n",
- own_id, GNUNET_i2s (peer));
- p->core_mq = NULL;
+ GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
+ cp->connectivity_suggestion = NULL;
}
- direct_path = pop_direct_path (p);
- if (NULL != p->connections)
+ if (NULL != cp->search_h)
{
- GNUNET_CONTAINER_multishortmap_iterate (p->connections,
- &notify_broken,
- p);
- GNUNET_CONTAINER_multishortmap_destroy (p->connections);
- p->connections = NULL;
+ GCD_search_stop (cp->search_h);
+ cp->search_h = NULL;
}
- GNUNET_STATISTICS_update (stats,
- "# peers",
- -1,
- GNUNET_NO);
- path_destroy (direct_path);
- GCC_check_connections ();
-}
-
-
-/******************************************************************************/
-/******************************************************************************/
-/******************************************************************************/
-/******************************************************************************/
-/******************************************************************************/
-
-/**
- * Check if the create_connection message has the appropriate size.
- *
- * @param cls Closure (unused).
- * @param msg Message to check.
- *
- * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
- */
-static int
-check_create (void *cls, const struct GNUNET_CADET_ConnectionCreateMessage *msg)
-{
- uint16_t size;
-
- size = ntohs (msg->header.size);
- if (size < sizeof (*msg))
+ return;
+ }
+ if (NULL == cp->core_mq)
+ {
+ /* Lacks direct connection, try to create one by querying the DHT */
+ if ( (NULL == cp->search_h) &&
+ (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
+ cp->search_h
+ = GCD_search (&cp->pid);
+ }
+ else
+ {
+ /* Have direct connection, stop DHT search if active */
+ if (NULL != cp->search_h)
{
- GNUNET_break_op (0);
- return GNUNET_NO;
+ GCD_search_stop (cp->search_h);
+ cp->search_h = NULL;
}
- return GNUNET_YES;
-}
-
-/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
- */
-static void
-handle_create (void *cls, const struct GNUNET_CADET_ConnectionCreateMessage *msg)
-{
- struct CadetPeer *peer = cls;
- GCC_handle_create (peer, msg);
-}
-
-
-/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
- */
-static void
-handle_confirm (void *cls, const struct GNUNET_CADET_ConnectionCreateAckMessage *msg)
-{
- struct CadetPeer *peer = cls;
- GCC_handle_confirm (peer, msg);
-}
-
+ }
-/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
- */
-static void
-handle_broken (void *cls, const struct GNUNET_CADET_ConnectionBrokenMessage *msg)
-{
- struct CadetPeer *peer = cls;
- GCC_handle_broken (peer, msg);
+ /* If we have a tunnel, our urge for connections is much bigger */
+ strength = (NULL != cp->t) ? 32 : 1;
+ if (NULL != cp->connectivity_suggestion)
+ GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
+ cp->connectivity_suggestion
+ = GNUNET_ATS_connectivity_suggest (ats_ch,
+ &cp->pid,
+ strength);
}
/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY
+ * This peer may no longer be needed, consider cleaning it up.
*
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
+ * @param cp peer to clean up
*/
static void
-handle_destroy (void *cls, const struct GNUNET_CADET_ConnectionDestroyMessage *msg)
-{
- struct CadetPeer *peer = cls;
- GCC_handle_destroy (peer, msg);
-}
+consider_peer_destroy (struct CadetPeer *cp);
/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK
+ * We really no longere care about a peer, stop hogging memory with paths to it.
+ * Afterwards, see if there is more to be cleaned up about this peer.
*
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
+ * @param cls a `struct CadetPeer`.
*/
static void
-handle_ack (void *cls, const struct GNUNET_CADET_ConnectionEncryptedAckMessage *msg)
+drop_paths (void *cls)
{
- struct CadetPeer *peer = cls;
- GCC_handle_ack (peer, msg);
-}
+ struct CadetPeer *cp = cls;
+ struct CadetPeerPath *path;
-
-/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
- */
-static void
-handle_poll (void *cls, const struct GNUNET_CADET_ConnectionHopByHopPollMessage *msg)
-{
- struct CadetPeer *peer = cls;
- GCC_handle_poll (peer, msg);
+ cp->destroy_task = NULL;
+ while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
+ GCPP_release (path);
+ consider_peer_destroy (cp);
}
/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX
+ * This peer may no longer be needed, consider cleaning it up.
*
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
+ * @param cp peer to clean up
*/
static void
-handle_kx (void *cls, const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
-{
- struct CadetPeer *peer = cls;
- GCC_handle_kx (peer, msg);
-}
-
-
-/**
- * Check if the encrypted message has the appropriate size.
- *
- * @param cls Closure (unused).
- * @param msg Message to check.
- *
- * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
- */
-static int
-check_encrypted (void *cls, const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
+consider_peer_destroy (struct CadetPeer *cp)
{
- uint16_t size;
- uint16_t minimum_size;
-
- size = ntohs (msg->header.size);
- minimum_size = sizeof (struct GNUNET_CADET_TunnelEncryptedMessage)
- + sizeof (struct GNUNET_MessageHeader);
-
- if (size < minimum_size)
- {
- GNUNET_break_op (0);
- return GNUNET_NO;
- }
- return GNUNET_YES;
-}
+ struct GNUNET_TIME_Relative exp;
-/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED.
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
- */
-static void
-handle_encrypted (void *cls, const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
-{
- struct CadetPeer *peer = cls;
- GCC_handle_encrypted (peer, msg);
-}
-
-
-/**
- * To be called on core init/fail.
- *
- * @param cls Closure (config)
- * @param identity The public identity of this peer.
- */
-static void
-core_init_notify (void *cls,
- const struct GNUNET_PeerIdentity *identity);
-
-
-static void
-connect_to_core (const struct GNUNET_CONFIGURATION_Handle *c)
-{
- struct GNUNET_MQ_MessageHandler core_handlers[] = {
- GNUNET_MQ_hd_var_size (create,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE,
- struct GNUNET_CADET_ConnectionCreateMessage,
- NULL),
- GNUNET_MQ_hd_fixed_size (confirm,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK,
- struct GNUNET_CADET_ConnectionCreateAckMessage,
- NULL),
- GNUNET_MQ_hd_fixed_size (broken,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN,
- struct GNUNET_CADET_ConnectionBrokenMessage,
- NULL),
- GNUNET_MQ_hd_fixed_size (destroy,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY,
- struct GNUNET_CADET_ConnectionDestroyMessage,
- NULL),
- GNUNET_MQ_hd_fixed_size (ack,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK,
- struct GNUNET_CADET_ConnectionEncryptedAckMessage,
- NULL),
- GNUNET_MQ_hd_fixed_size (poll,
- GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL,
- struct GNUNET_CADET_ConnectionHopByHopPollMessage,
- NULL),
- GNUNET_MQ_hd_fixed_size (kx,
- GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX,
- struct GNUNET_CADET_TunnelKeyExchangeMessage,
- NULL),
- GNUNET_MQ_hd_var_size (encrypted,
- GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED,
- struct GNUNET_CADET_TunnelEncryptedMessage,
- NULL),
- GNUNET_MQ_handler_end ()
- };
- core_handle = GNUNET_CORE_connect (c, NULL,
- &core_init_notify,
- &core_connect_handler,
- &core_disconnect_handler,
- core_handlers);
-}
-
-/******************************************************************************/
-/******************************************************************************/
-/******************************************************************************/
-/******************************************************************************/
-/******************************************************************************/
-
-/**
- * To be called on core init/fail.
- *
- * @param cls Closure (config)
- * @param identity The public identity of this peer.
- */
-static void
-core_init_notify (void *cls,
- const struct GNUNET_PeerIdentity *core_identity)
-{
- const struct GNUNET_CONFIGURATION_Handle *c = cls;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Core init\n");
- if (0 != memcmp (core_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 (core_identity));
- LOG (GNUNET_ERROR_TYPE_ERROR, " my id %s\n", GNUNET_i2s (&my_full_id));
- GNUNET_CORE_disconnect (core_handle);
- connect_to_core (c);
- return;
- }
- GML_start ();
+ if (NULL != cp->destroy_task)
+ {
+ GNUNET_SCHEDULER_cancel (cp->destroy_task);
+ cp->destroy_task = NULL;
+ }
+ if (NULL != cp->t)
+ return; /* still relevant! */
+ if (NULL != cp->core_mq)
+ return; /* still relevant! */
+ if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
+ return; /* still relevant! */
+ if ( (NULL != cp->path_heap) &&
+ (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) )
+ {
+ cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
+ &drop_paths,
+ cp);
+ return;
+ }
+ if (0 != cp->num_paths)
+ return; /* still relevant! */
+ if (NULL != cp->hello)
+ {
+ /* relevant only until HELLO expires */
+ exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
+ cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
+ &destroy_peer,
+ cp);
+ return;
+ }
+ cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
+ &destroy_peer,
+ cp);
}
-/******************************************************************************/
-/******************************** STATIC ***********************************/
-/******************************************************************************/
-
-
/**
- * Get priority for a queued message.
- *
- * @param q Queued message
- *
- * @return CORE priority to use.
+ * Set the message queue to @a mq for peer @a cp and notify watchers.
*
- * FIXME make static
- * FIXME use when sending
+ * @param cp peer to modify
+ * @param mq message queue to set (can be NULL)
*/
-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 == GCC_is_origin (q->c, q->c_fwd))
+void
+GCP_set_mq (struct CadetPeer *cp,
+ struct GNUNET_MQ_Handle *mq)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Message queue for peer %s is now %p\n",
+ GCP_2s (cp),
+ mq);
+ cp->core_mq = mq;
+ for (struct GCP_MessageQueueManager *mqm = cp->mqm_head, *next;
+ NULL != mqm;
+ mqm = next)
+ {
+ /* Save next pointer in case mqm gets freed by the callback */
+ next = mqm->next;
+ if (NULL == mq)
{
- low = GNUNET_CORE_PRIO_BEST_EFFORT;
- high = GNUNET_CORE_PRIO_URGENT;
+ if (NULL != mqm->env)
+ {
+ GNUNET_MQ_discard (mqm->env);
+ mqm->env = NULL;
+ mqm->cb (mqm->cb_cls,
+ GNUNET_SYSERR);
+ }
+ else
+ {
+ mqm->cb (mqm->cb_cls,
+ GNUNET_NO);
+ }
}
else
{
- low = GNUNET_CORE_PRIO_URGENT;
- high = GNUNET_CORE_PRIO_CRITICAL_CONTROL;
+ GNUNET_assert (NULL == mqm->env);
+ mqm->cb (mqm->cb_cls,
+ GNUNET_YES);
}
+ }
+ if ( (NULL != mq) ||
+ (NULL != cp->t) )
+ consider_peer_activate (cp);
+ else
+ consider_peer_destroy (cp);
- /* Bulky payload has lower priority, control traffic has higher. */
- if (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED == q->type)
- return low;
- return high;
-}
-
-
-/**
- * Cancel all messages queued to CORE MQ towards this peer.
- *
- * @param peer Peer towards which to cancel all messages.
- */
-static void
-cancel_queued_messages (struct CadetPeer *peer)
-{
- while (NULL != peer->q_head)
- {
- struct CadetPeerQueue *q;
-
- q = peer->q_head;
- call_peer_cont (q, GNUNET_NO);
- GNUNET_free (q);
- }
-}
-
-
-/**
- * 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_INFO,
- "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, " peer not in peermap!!\n");
- }
- GCP_stop_search (peer);
- 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;
- }
- if (NULL != peer->tunnel)
- GCT_destroy_empty (peer->tunnel);
- if (NULL != peer->connections)
- {
- GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (peer->connections));
- GNUNET_CONTAINER_multishortmap_destroy (peer->connections);
- peer->connections = NULL;
- }
- if (NULL != peer->hello_offer)
- {
- GNUNET_TRANSPORT_offer_hello_cancel (peer->hello_offer);
- peer->hello_offer = NULL;
- }
- if (NULL != peer->connectivity_suggestion)
- {
- GNUNET_ATS_connectivity_suggest_cancel (peer->connectivity_suggestion);
- peer->connectivity_suggestion = NULL;
- }
- cancel_queued_messages (peer);
+ if ( (NULL != mq) &&
+ (NULL != cp->t) )
+ {
+ /* have a new, direct path to the target, notify tunnel */
+ struct CadetPeerPath *path;
- GNUNET_free_non_null (peer->hello);
- GNUNET_free (peer);
- return GNUNET_OK;
+ path = GCPP_get_path_from_route (1,
+ &cp->pid);
+ GCT_consider_path (cp->t,
+ path,
+ 0);
+ }
}
/**
- * Iterator over peer hash map entries to destroy the peer during in_shutdown.
+ * Debug function should NEVER return true in production code, useful to
+ * simulate losses for testcases.
*
- * @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.
+ * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
*/
static int
-shutdown_peer (void *cls,
- const struct GNUNET_PeerIdentity *key,
- void *value)
+should_I_drop (void)
{
- struct CadetPeer *p = value;
- struct CadetTunnel *t = p->tunnel;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " shutting down %s\n", GCP_2s (p));
- if (NULL != t)
- GCT_destroy (t);
- p->tunnel = NULL;
- peer_destroy (p);
+ if (0 == drop_percent)
+ return GNUNET_NO;
+ if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+ 101) < drop_percent)
return GNUNET_YES;
+ return GNUNET_NO;
}
/**
- * Check if peer is searching for a path (either active or delayed search).
- *
- * @param peer Peer to check
- * @return #GNUNET_YES if there is a search active.
- * #GNUNET_NO otherwise.
- */
-static int
-is_searching (const struct CadetPeer *peer)
-{
- return ( (NULL == peer->search_h) &&
- (NULL == peer->search_delayed) ) ?
- GNUNET_NO : GNUNET_YES;
-}
-
-
-/**
- * @brief Start a search for a peer.
+ * Function called when CORE took one of the messages from
+ * a message queue manager and transmitted it.
*
- * @param cls Closure (Peer to search for).
+ * @param cls the `struct CadetPeeer` where we made progress
*/
static void
-delayed_search (void *cls)
-{
- struct CadetPeer *peer = cls;
-
- peer->search_delayed = NULL;
- GCC_check_connections ();
- GCP_start_search (peer);
- GCC_check_connections ();
-}
+mqm_send_done (void *cls);
/**
- * Returns if peer is used (has a tunnel or is neighbor).
+ * Transmit current envelope from this @a mqm.
*
- * @param peer Peer to check.
- * @return #GNUNET_YES if peer is in use.
+ * @param mqm mqm to transmit message for now
*/
-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)
+static void
+mqm_execute (struct GCP_MessageQueueManager *mqm)
{
- 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;
+ struct CadetPeer *cp = mqm->cp;
- if (abs->abs_value_us < p->last_contact.abs_value_us)
- abs->abs_value_us = p->last_contact.abs_value_us;
-
- return GNUNET_YES;
+ /* Move ready pointer to the next entry that might be ready. */
+ if ( (mqm == cp->mqm_ready_ptr) &&
+ (NULL != mqm->next) )
+ cp->mqm_ready_ptr = mqm->next;
+ /* Move entry to the end of the DLL, to be fair. */
+ if (mqm != cp->mqm_tail)
+ {
+ GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
+ cp->mqm_tail,
+ mqm);
+ GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
+ cp->mqm_tail,
+ mqm);
+ }
+ cp->mqm_ready_counter--;
+ if (GNUNET_YES == should_I_drop ())
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "DROPPING message to peer %s from MQM %p\n",
+ GCP_2s (cp),
+ mqm);
+ GNUNET_MQ_discard (mqm->env);
+ mqm->env = NULL;
+ mqm_send_done (cp);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending to peer %s from MQM %p\n",
+ GCP_2s (cp),
+ mqm);
+ GNUNET_MQ_send (cp->core_mq,
+ mqm->env);
+ mqm->env = NULL;
+ }
+ mqm->cb (mqm->cb_cls,
+ GNUNET_YES);
}
/**
- * Iterator over all the peers to remove the oldest entry.
+ * Find the next ready message in the queue (starting
+ * the search from the `cp->mqm_ready_ptr`) and if possible
+ * execute the transmission.
*
- * @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.
+ * @param cp peer to try to send the next ready message to
*/
static void
-peer_delete_oldest (void)
+send_next_ready (struct CadetPeer *cp)
{
- 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);
-}
-
+ struct GCP_MessageQueueManager *mqm;
-/**
- * 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 == GCT_is_path_used (peer->tunnel, p))
- continue; /* If path is already in use, skip it. */
-
- if ((cost = GCT_get_path_cost (peer->tunnel, p)) < best_cost)
- {
- best_cost = cost;
- best_p = p;
- }
- }
- return best_p;
+ if (0 == cp->mqm_ready_counter)
+ return;
+ while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
+ (NULL == mqm->env) )
+ cp->mqm_ready_ptr = mqm->next;
+ if (NULL == mqm)
+ return; /* nothing to do */
+ mqm_execute (mqm);
}
/**
- * 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.
+ * Function called when CORE took one of the messages from
+ * a message queue manager and transmitted it.
*
- * @param cls Closure (peer towards a path has been found).
- * @param path Path created from the DHT query. Will be freed afterwards.
+ * @param cls the `struct CadetPeeer` where we made progress
*/
static void
-search_handler (void *cls, const struct CadetPeerPath *path)
+mqm_send_done (void *cls)
{
- struct CadetPeer *peer = cls;
- unsigned int connection_count;
-
- GCC_check_connections ();
- GCP_add_path_to_all (path, GNUNET_NO);
-
- /* Count connections */
- connection_count = GCT_count_connections (peer->tunnel);
+ struct CadetPeer *cp = cls;
- /* If we already have our minimum (or more) connections, it's enough */
- if (CONNECTIONS_PER_TUNNEL <= connection_count)
- {
- GCC_check_connections ();
- return;
- }
-
- if (CADET_TUNNEL_SEARCHING == GCT_get_cstate (peer->tunnel))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " ... connect!\n");
- GCP_connect (peer);
- }
- GCC_check_connections ();
-}
-
-
-/**
- * Test if a message type is connection management traffic
- * or regular payload traffic.
- *
- * @param type Message type.
- *
- * @return #GNUNET_YES if connection management, #GNUNET_NO otherwise.
- */
-static int
-is_connection_management (uint16_t type)
-{
- return type == GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK ||
- type == GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending to peer %s completed\n",
+ GCP_2s (cp));
+ send_next_ready (cp);
}
/**
- * Debug function should NEVER return true in production code, useful to
- * simulate losses for testcases.
+ * Send the message in @a env to @a cp.
*
- * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
+ * @param mqm the message queue manager to use for transmission
+ * @param env envelope with the message to send; must NOT
+ * yet have a #GNUNET_MQ_notify_sent() callback attached to it
*/
-static int
-should_I_drop (void)
+void
+GCP_send (struct GCP_MessageQueueManager *mqm,
+ struct GNUNET_MQ_Envelope *env)
{
- if (0 == drop_percent)
- return GNUNET_NO;
+ struct CadetPeer *cp = mqm->cp;
- if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 101) < drop_percent)
- return GNUNET_YES;
-
- return GNUNET_NO;
+ GNUNET_assert (NULL != env);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Queueing message to peer %s in MQM %p\n",
+ GCP_2s (cp),
+ mqm);
+ GNUNET_assert (NULL != cp->core_mq);
+ GNUNET_assert (NULL == mqm->env);
+ GNUNET_MQ_notify_sent (env,
+ &mqm_send_done,
+ cp);
+ mqm->env = env;
+ cp->mqm_ready_counter++;
+ if (mqm != cp->mqm_ready_ptr)
+ cp->mqm_ready_ptr = cp->mqm_head;
+ if (1 == cp->mqm_ready_counter)
+ cp->mqm_ready_ptr = mqm;
+ if (0 != GNUNET_MQ_get_length (cp->core_mq))
+ return;
+ send_next_ready (cp);
}
-/******************************************************************************/
-/******************************** API ***********************************/
-/******************************************************************************/
-
/**
- * Call the continuation after a message has been sent or dropped.
+ * Function called to destroy a peer now.
*
- * This funcion removes the message from the queue.
- *
- * @param q Queue handle.
- * @param sent #GNUNET_YES if was sent to CORE, #GNUNET_NO if dropped.
+ * @param cls NULL
+ * @param pid identity of the peer (unused)
+ * @param value the `struct CadetPeer` to clean up
+ * @return #GNUNET_OK (continue to iterate)
*/
-static void
-call_peer_cont (struct CadetPeerQueue *q, int sent)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " core mq just sent %s\n", GC_m2s (q->type));
- if (NULL != q->cont)
- {
- struct GNUNET_TIME_Relative wait_time;
-
- wait_time = GNUNET_TIME_absolute_get_duration (q->queue_timestamp);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " calling callback on %s after %s\n",
- GCC_2s (q->c),
- GNUNET_STRINGS_relative_time_to_string (wait_time, GNUNET_NO));
- q->cont (q->cont_cls,
- q->c, q->c_fwd, sent,
- q->type,
- q->payload_type,
- q->payload_id,
- q->size, wait_time);
- q->cont = NULL;
- }
- GNUNET_CONTAINER_DLL_remove (q->peer->q_head, q->peer->q_tail, q);
-}
-
-
-/**
- * Function called by MQ when a message is sent to CORE.
- *
- * @param cls Closure (queue handle).
- */
-static void
-mq_sent (void *cls)
+static int
+destroy_iterator_cb (void *cls,
+ const struct GNUNET_PeerIdentity *pid,
+ void *value)
{
- struct CadetPeerQueue *q = cls;
+ struct CadetPeer *cp = value;
- if (GNUNET_NO == q->management_traffic)
- {
- q->peer->queue_n--;
- }
- call_peer_cont (q, GNUNET_YES);
- GNUNET_free (q);
+ if (NULL != cp->destroy_task)
+ {
+ GNUNET_SCHEDULER_cancel (cp->destroy_task);
+ cp->destroy_task = NULL;
+ }
+ destroy_peer (cp);
+ return GNUNET_OK;
}
/**
- * Finish the drop operation.
- *
- * @param cls queue entry to finish drop for
+ * Clean up all entries about all peers.
+ * Must only be called after all tunnels, CORE-connections and
+ * connections are down.
*/
-static void
-drop_cb (void *cls)
+void
+GCP_destroy_all_peers ()
{
- struct CadetPeerQueue *q = cls;
-
- GNUNET_MQ_discard (q->env);
- call_peer_cont (q, GNUNET_YES);
- GNUNET_free (q);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Destroying all peers now\n");
+ GNUNET_CONTAINER_multipeermap_iterate (peers,
+ &destroy_iterator_cb,
+ NULL);
}
/**
- * @brief Send a message to another peer (using CORE).
+ * Drop all paths owned by this peer, and do not
+ * allow new ones to be added: We are shutting down.
*
- * @param peer Peer towards which to queue the message.
- * @param message Message to send.
- * @param payload_type Type of the message's payload, for debug messages.
- * 0 if the message is a retransmission (unknown payload).
- * UINT16_MAX if the message does not have payload.
- * @param payload_id ID of the payload (MID, ACK #, etc)
- * @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 sent the message.
- * @param cont_cls Closure for @c cont.
- *
- * @return A handle to the message in the queue or NULL (if dropped).
+ * @param cp peer to drop paths to
*/
-struct CadetPeerQueue *
-GCP_send (struct CadetPeer *peer,
- const struct GNUNET_MessageHeader *message,
- uint16_t payload_type,
- struct CadetEncryptedMessageIdentifier payload_id,
- struct CadetConnection *c,
- int fwd,
- GCP_sent cont,
- void *cont_cls)
+void
+GCP_drop_owned_paths (struct CadetPeer *cp)
{
- struct CadetPeerQueue *q;
- uint16_t type;
- uint16_t size;
-
- GCC_check_connections ();
- type = ntohs (message->type);
- size = ntohs (message->size);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "que %s (%s %4u) on conn %s (%p) %s towards %s (size %u)\n",
- GC_m2s (type), GC_m2s (payload_type),
- ntohl (payload_id.pid),
- GCC_2s (c), c, GC_f2s (fwd), GCP_2s (peer), size);
-
- if (NULL == peer->connections)
- {
- /* We are not connected to this peer, ignore request. */
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_INFO, "%s not a neighbor\n", GCP_2s (peer));
- GNUNET_STATISTICS_update (stats, "# messages dropped due to wrong hop", 1,
- GNUNET_NO);
- return NULL;
- }
+ struct CadetPeerPath *path;
- q = GNUNET_new (struct CadetPeerQueue);
- q->env = GNUNET_MQ_msg_copy (message);
- q->peer = peer;
- q->cont = cont;
- q->cont_cls = cont_cls;
- q->queue_timestamp = GNUNET_TIME_absolute_get ();
- q->management_traffic = is_connection_management (type);
- q->type = type;
- q->size = size;
- q->payload_type = payload_type;
- q->payload_id = payload_id;
- q->c = c;
- q->c_fwd = fwd;
- GNUNET_MQ_notify_sent (q->env, &mq_sent, q);
- GNUNET_CONTAINER_DLL_insert (peer->q_head, peer->q_tail, q);
-
- if (GNUNET_YES == q->management_traffic)
- {
- GNUNET_MQ_send (peer->core_mq, q->env); // FIXME implement "_urgent", use
- }
- else
- {
- if (GNUNET_YES == should_I_drop ())
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "DD %s (%s %u) on conn %s %s (random drop for testing)\n",
- GC_m2s (q->type),
- GC_m2s (q->payload_type),
- ntohl (q->payload_id.pid),
- GCC_2s (c),
- GC_f2s (q->c_fwd));
- q->drop_task = GNUNET_SCHEDULER_add_now (&drop_cb,
- q);
- return q;
- }
- GNUNET_MQ_send (peer->core_mq, q->env);
- peer->queue_n++;
- }
-
- GCC_check_connections ();
- return q;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Destroying all paths to %s\n",
+ GCP_2s (cp));
+ while (NULL != (path =
+ GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
+ GCPP_release (path);
+ GNUNET_CONTAINER_heap_destroy (cp->path_heap);
+ cp->path_heap = NULL;
}
/**
- * Cancel sending a message. Message must have been sent with
- * #GCP_send before. May not be called after the notify sent
- * callback has been called.
- *
- * It DOES call the continuation given to #GCP_send.
+ * Add an entry to the DLL of all of the paths that this peer is on.
*
- * @param q Queue handle to cancel
+ * @param cp peer to modify
+ * @param entry an entry on a path
+ * @param off offset of this peer on the path
*/
void
-GCP_send_cancel (struct CadetPeerQueue *q)
-{
- if (NULL != q->drop_task)
+GCP_path_entry_add (struct CadetPeer *cp,
+ struct CadetPeerPathEntry *entry,
+ unsigned int off)
+{
+ GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
+ off));
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Discovered that peer %s is on path %s at offset %u\n",
+ GCP_2s (cp),
+ GCPP_2s (entry->path),
+ off);
+ if (off >= cp->path_dll_length)
{
- GNUNET_SCHEDULER_cancel (q->drop_task);
- q->drop_task = NULL;
- GNUNET_MQ_discard (q->env);
+ unsigned int len = cp->path_dll_length;
+
+ GNUNET_array_grow (cp->path_heads,
+ len,
+ off + 4);
+ GNUNET_array_grow (cp->path_tails,
+ cp->path_dll_length,
+ off + 4);
}
- else
+ GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
+ cp->path_tails[off],
+ entry);
+ cp->off_sum += off;
+ cp->num_paths++;
+
+ /* If we have a tunnel to this peer, tell the tunnel that there is a
+ new path available. */
+ if (NULL != cp->t)
+ GCT_consider_path (cp->t,
+ entry->path,
+ off);
+
+ if ( (NULL != cp->search_h) &&
+ (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
{
- GNUNET_MQ_send_cancel (q->env);
+ /* Now I have enough paths, stop search */
+ GCD_search_stop (cp->search_h);
+ cp->search_h = NULL;
+ }
+ if (NULL != cp->destroy_task)
+ {
+ /* paths changed, this resets the destroy timeout counter
+ and aborts a destroy task that may no longer be valid
+ to have (as we now have more paths via this peer). */
+ consider_peer_destroy (cp);
}
- call_peer_cont (q, GNUNET_NO);
- GNUNET_free (q);
}
/**
- * Initialize the peer subsystem.
+ * Remove an entry from the DLL of all of the paths that this peer is on.
*
- * @param c Configuration.
- */
-void
-GCP_init (const struct GNUNET_CONFIGURATION_Handle *c)
-{
- cfg = c;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "GCP_init\n");
- in_shutdown = GNUNET_NO;
- 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");
- }
- ats_ch = GNUNET_ATS_connectivity_init (c);
- connect_to_core (c);
- if (NULL == core_handle)
- {
- GNUNET_break (0);
- GNUNET_SCHEDULER_shutdown ();
- }
-}
-
-
-/**
- * Shut down the peer subsystem.
+ * @param cp peer to modify
+ * @param entry an entry on a path
+ * @param off offset of this peer on the path
*/
void
-GCP_shutdown (void)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Shutting down peer subsystem\n");
- in_shutdown = GNUNET_YES;
- if (NULL != core_handle)
- {
- GNUNET_CORE_disconnect (core_handle);
- core_handle = NULL;
- }
- GNUNET_PEER_change_rc (myid, -1);
- /* With MQ API, CORE calls the disconnect handler for every peer
- * after calling GNUNET_CORE_disconnect, shutdown must occur *after* that.
- */
- GNUNET_CONTAINER_multipeermap_iterate (peers,
- &shutdown_peer,
- NULL);
- if (NULL != ats_ch)
- {
- GNUNET_ATS_connectivity_done (ats_ch);
- ats_ch = NULL;
- }
- GNUNET_CONTAINER_multipeermap_destroy (peers);
- peers = NULL;
-}
-
-
-/**
- * Retrieve the CadetPeer stucture associated with the peer. Optionally create
- * one and insert it in the appropriate structures if the peer is not known yet.
- *
- * @param peer_id Full identity of the peer.
- * @param create #GNUNET_YES if a new peer should be created if unknown.
- * #GNUNET_NO otherwise.
- *
- * @return Existing or newly created peer structure.
- * NULL if unknown and not requested @a create
- */
-struct CadetPeer *
-GCP_get (const struct GNUNET_PeerIdentity *peer_id, int create)
-{
- 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_assert (GNUNET_OK ==
- GNUNET_CONTAINER_multipeermap_put (peers,
- peer_id,
- peer,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
- peer->id = GNUNET_PEER_intern (peer_id);
- }
- peer->last_contact = GNUNET_TIME_absolute_get ();
-
- return peer;
-}
-
-
-/**
- * Retrieve the CadetPeer stucture associated with the
- * peer. Optionally create one and insert it in the appropriate
- * structures if the peer is not known yet.
- *
- * @param peer Short identity of the peer.
- * @param create #GNUNET_YES if a new peer should be created if unknown.
- * #GNUNET_NO otherwise.
- *
- * @return Existing or newly created peer structure.
- * NULL if unknown and not requested @a create
- */
-struct CadetPeer *
-GCP_get_short (const GNUNET_PEER_Id peer, int create)
-{
- return GCP_get (GNUNET_PEER_resolve2 (peer), create);
+GCP_path_entry_remove (struct CadetPeer *cp,
+ struct CadetPeerPathEntry *entry,
+ unsigned int off)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Removing knowledge about peer %s beging on path %s at offset %u\n",
+ GCP_2s (cp),
+ GCPP_2s (entry->path),
+ off);
+ GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
+ cp->path_tails[off],
+ entry);
+ GNUNET_assert (0 < cp->num_paths);
+ cp->off_sum -= off;
+ cp->num_paths--;
+ if ( (NULL == cp->core_mq) &&
+ (NULL != cp->t) &&
+ (NULL == cp->search_h) &&
+ (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
+ cp->search_h
+ = GCD_search (&cp->pid);
+ if (NULL == cp->destroy_task)
+ {
+ /* paths changed, we might now be ready for destruction, check again */
+ consider_peer_destroy (cp);
+ }
}
/**
- * Function called once #GNUNET_TRANSPORT_offer_hello() is done.
- * Marks the operation as finished.
+ * Prune down the number of paths to this peer, we seem to
+ * have way too many.
*
- * @param cls Closure (our `struct CadetPeer`).
+ * @param cls the `struct CadetPeer` to maintain the path heap for
*/
static void
-hello_offer_done (void *cls)
+path_heap_cleanup (void *cls)
{
- struct CadetPeer *peer = cls;
+ struct CadetPeer *cp = cls;
+ struct CadetPeerPath *root;
- peer->hello_offer = NULL;
+ cp->heap_cleanup_task = NULL;
+ while (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
+ 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
+ {
+ /* Now we have way too many, drop least desirable UNLESS it is in use!
+ (Note that this intentionally keeps highly desireable, but currently
+ unused paths around in the hope that we might be able to switch, even
+ if the number of paths exceeds the threshold.) */
+ root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
+ GNUNET_assert (NULL != root);
+ if (NULL !=
+ GCPP_get_connection (root,
+ cp,
+ GCPP_get_length (root) - 1))
+ break; /* can't fix */
+ /* Got plenty of paths to this destination, and this is a low-quality
+ one that we don't care about. Allow it to die. */
+ GNUNET_assert (root ==
+ GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
+ GCPP_release (root);
+ }
}
/**
- * 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.
+ * Try adding a @a path to this @a peer. If the peer already
+ * has plenty of paths, return NULL.
*
- * @param peer Peer to connect to.
+ * @param cp peer to which the @a path leads to
+ * @param path a path looking for an owner; may not be fully initialized yet!
+ * @param off offset of @a cp in @a path
+ * @param force force attaching the path
+ * @return NULL if this peer does not care to become a new owner,
+ * otherwise the node in the peer's path heap for the @a path.
*/
-void
-GCP_connect (struct CadetPeer *peer)
+struct GNUNET_CONTAINER_HeapNode *
+GCP_attach_path (struct CadetPeer *cp,
+ struct CadetPeerPath *path,
+ unsigned int off,
+ int force)
{
- struct CadetTunnel *t;
- struct CadetPeerPath *path;
- struct CadetConnection *c;
- int rerun_search;
-
- GCC_check_connections ();
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "peer_connect towards %s\n",
- GCP_2s (peer));
- /* If we have a current hello, try to connect using it. */
- GCP_try_connect (peer);
+ GNUNET_CONTAINER_HeapCostType desirability;
+ struct CadetPeerPath *root;
+ GNUNET_CONTAINER_HeapCostType root_desirability;
+ struct GNUNET_CONTAINER_HeapNode *hn;
- t = peer->tunnel;
- c = NULL;
- rerun_search = GNUNET_NO;
-
- if (NULL != peer->path_head)
+ GNUNET_assert (off == GCPP_get_length (path) - 1);
+ GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
+ off));
+ if (NULL == cp->path_heap)
+ {
+ /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
+ GNUNET_assert (GNUNET_NO == force);
+ return NULL;
+ }
+ desirability = GCPP_get_desirability (path);
+ if (GNUNET_NO == force)
+ {
+ /* FIXME: desirability is not yet initialized; tricky! */
+ if (GNUNET_NO ==
+ GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
+ (void **) &root,
+ &root_desirability))
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " some path exists\n");
- path = peer_get_best_path (peer);
- if (NULL != path)
- {
- char *s;
-
- s = path_2s (path);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " path to use: %s\n", s);
- GNUNET_free (s);
-
- c = GCT_use_path (t, path);
- 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
- * hashmaps 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.
- *
- * GCT_use_path -> GCC_new -> register_neighbors takes care of
- * updating statistics about this issue.
- */
- rerun_search = GNUNET_YES;
- }
- else
- {
- GCC_send_create (c);
- return;
- }
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " but is NULL, all paths are in use\n");
- }
+ root = NULL;
+ root_desirability = 0;
}
- if (GNUNET_YES == rerun_search)
+ if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
+ (desirability < root_desirability) )
{
- struct GNUNET_TIME_Relative delay;
-
- GCP_stop_search (peer);
- delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100);
- peer->search_delayed = GNUNET_SCHEDULER_add_delayed (delay,
- &delayed_search,
- peer);
- GCC_check_connections ();
- return;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Decided to not attach path %p to peer %s due to undesirability\n",
+ GCPP_2s (path),
+ GCP_2s (cp));
+ return NULL;
}
+ }
- if (GNUNET_NO == is_searching (peer))
- GCP_start_search (peer);
- GCC_check_connections ();
-}
-
-
-/**
- * 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
-GCP_is_neighbor (const struct CadetPeer *peer)
-{
- struct CadetPeerPath *path;
-
- if (NULL == peer->connections)
- return GNUNET_NO;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Attaching path %s to peer %s (%s)\n",
+ GCPP_2s (path),
+ GCP_2s (cp),
+ (GNUNET_NO == force) ? "desirable" : "forced");
- for (path = peer->path_head; NULL != path; path = path->next)
- {
- if (3 > path->length)
- return GNUNET_YES;
- }
+ /* Yes, we'd like to add this path, add to our heap */
+ hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
+ path,
+ desirability);
- /* Is not a neighbor but connections is not NULL, probably disconnecting */
- return GNUNET_NO;
+ /* Consider maybe dropping other paths because of the new one */
+ if ( (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
+ 2 * DESIRED_CONNECTIONS_PER_TUNNEL) &&
+ (NULL != cp->heap_cleanup_task) )
+ cp->heap_cleanup_task = GNUNET_SCHEDULER_add_now (&path_heap_cleanup,
+ cp);
+ return hn;
}
/**
- * 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.
+ * This peer can no longer own @a path as the path
+ * has been extended and a peer further down the line
+ * is now the new owner.
*
- * Does not generate any traffic, just creates the local data structures.
- *
- * @param peer Peer towards which to create the tunnel.
+ * @param cp old owner of the @a path
+ * @param path path where the ownership is lost
+ * @param hn note in @a cp's path heap that must be deleted
*/
void
-GCP_add_tunnel (struct CadetPeer *peer)
+GCP_detach_path (struct CadetPeer *cp,
+ struct CadetPeerPath *path,
+ struct GNUNET_CONTAINER_HeapNode *hn)
{
- GCC_check_connections ();
- if (NULL != peer->tunnel)
- return;
- peer->tunnel = GCT_new (peer);
- GCC_check_connections ();
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Detatching path %s from peer %s\n",
+ GCPP_2s (path),
+ GCP_2s (cp));
+ GNUNET_assert (path ==
+ GNUNET_CONTAINER_heap_remove_node (hn));
}
/**
- * 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.
+ * Add a @a connection to this @a cp.
*
- * @param peer Peer to add connection to.
- * @param c Connection to add.
- * @param pred #GNUNET_YES if we are predecessor, #GNUNET_NO if we are successor
+ * @param cp peer via which the @a connection goes
+ * @param cc the connection to add
*/
void
-GCP_add_connection (struct CadetPeer *peer,
- struct CadetConnection *c,
- int pred)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "adding connection %s\n",
- GCC_2s (c));
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "to peer %s\n",
- GCP_2s (peer));
- GNUNET_assert (NULL != peer->connections);
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CONTAINER_multishortmap_put (peer->connections,
- &GCC_get_id (c)->connection_of_tunnel,
- c,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Peer %s has now %u connections.\n",
- GCP_2s (peer),
- GNUNET_CONTAINER_multishortmap_size (peer->connections));
-}
-
-
-/**
- * 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 @c peer.
- * 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 *
-GCP_add_path (struct CadetPeer *peer,
- struct CadetPeerPath *path,
- int trusted)
-{
- struct CadetPeerPath *aux;
- unsigned int l;
- unsigned int l2;
-
- GCC_check_connections ();
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "adding path [%u] to peer %s\n",
- path->length, GCP_2s (peer));
-
- if (NULL == peer || NULL == path
- || 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);
- goto finish;
- }
- 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");
-
-finish:
- if (NULL != peer->tunnel
- && CONNECTIONS_PER_TUNNEL > GCT_count_connections (peer->tunnel)
- && 2 < path->length) /* Direct paths are handled by core_connect */
- {
- GCP_connect (peer);
- }
- GCC_check_connections ();
- return path;
+GCP_add_connection (struct CadetPeer *cp,
+ struct CadetConnection *cc)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Adding connection %s to peer %s\n",
+ GCC_2s (cc),
+ GCP_2s (cp));
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multishortmap_put (cp->connections,
+ &GCC_get_id (cc)->connection_of_tunnel,
+ cc,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ if (NULL != cp->destroy_task)
+ {
+ GNUNET_SCHEDULER_cancel (cp->destroy_task);
+ cp->destroy_task = NULL;
+ }
}
/**
- * 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?
+ * Remove a @a connection that went via this @a cp.
*
- * @return path if path was taken, pointer to existing duplicate if exists
- * NULL on error.
+ * @param cp peer via which the @a connection went
+ * @param cc the connection to remove
*/
-struct CadetPeerPath *
-GCP_add_path_to_origin (struct CadetPeer *peer,
- struct CadetPeerPath *path,
- int trusted)
+void
+GCP_remove_connection (struct CadetPeer *cp,
+ struct CadetConnection *cc)
{
- if (NULL == path)
- return NULL;
- path_invert (path);
- return GCP_add_path (peer, path, trusted);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Removing connection %s from peer %s\n",
+ GCC_2s (cc),
+ GCP_2s (cp));
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multishortmap_remove (cp->connections,
+ &GCC_get_id (cc)->connection_of_tunnel,
+ cc));
+ consider_peer_destroy (cp);
}
/**
- * Adds a path to the info of all the peers in the path
+ * Retrieve the CadetPeer stucture associated with the
+ * peer. Optionally create one and insert it in the appropriate
+ * structures if the peer is not known yet.
*
- * @param p Path to process.
- * @param confirmed Whether we know if the path works or not.
+ * @param peer_id Full identity of the peer.
+ * @param create #GNUNET_YES if a new peer should be created if unknown.
+ * #GNUNET_NO to return NULL if peer is unknown.
+ * @return Existing or newly created peer structure.
+ * NULL if unknown and not requested @a create
*/
-void
-GCP_add_path_to_all (const struct CadetPeerPath *p, int confirmed)
+struct CadetPeer *
+GCP_get (const struct GNUNET_PeerIdentity *peer_id,
+ int create)
{
- unsigned int i;
+ struct CadetPeer *cp;
- /* TODO: invert and add to origin */
- /* TODO: replace all "GCP_add_path" with this, make the other one static */
- GCC_check_connections ();
- for (i = 0; i < p->length && p->peers[i] != myid; i++) /* skip'em */ ;
- for (i++; i < p->length; i++)
- {
- struct CadetPeer *peer;
- struct CadetPeerPath *copy;
-
- peer = GCP_get_short (p->peers[i], GNUNET_YES);
- copy = path_duplicate (p);
- copy->length = i + 1;
- GCP_add_path (peer, copy, 3 > p->length ? GNUNET_NO : confirmed);
- }
- GCC_check_connections ();
+ cp = GNUNET_CONTAINER_multipeermap_get (peers,
+ peer_id);
+ if (NULL != cp)
+ return cp;
+ if (GNUNET_NO == create)
+ return NULL;
+ cp = GNUNET_new (struct CadetPeer);
+ cp->pid = *peer_id;
+ cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
+ GNUNET_YES);
+ cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multipeermap_put (peers,
+ &cp->pid,
+ cp,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating peer %s\n",
+ GCP_2s (cp));
+ return cp;
}
/**
- * Remove any path to the peer that has the exact same peers as the one given.
+ * Obtain the peer identity for a `struct CadetPeer`.
*
- * @param peer Peer to remove the path from.
- * @param path Path to remove. Is always destroyed .
+ * @param cp our peer handle
+ * @return the peer identity
*/
-void
-GCP_remove_path (struct CadetPeer *peer,
- struct CadetPeerPath *path)
+const struct GNUNET_PeerIdentity *
+GCP_get_id (struct CadetPeer *cp)
{
- struct CadetPeerPath *iter;
- struct CadetPeerPath *next;
-
- GCC_check_connections ();
- GNUNET_assert (myid == path->peers[0]);
- GNUNET_assert (peer->id == path->peers[path->length - 1]);
-
- LOG (GNUNET_ERROR_TYPE_INFO,
- "Removing path %p (%u) from %s\n",
- path, path->length, GCP_2s (peer));
-
- for (iter = peer->path_head; NULL != iter; iter = next)
- {
- next = iter->next;
- if (0 == path_cmp (path, iter))
- {
- GNUNET_CONTAINER_DLL_remove (peer->path_head,
- peer->path_tail,
- iter);
- if (iter != path)
- path_destroy (iter);
- }
- }
- path_destroy (path);
- GCC_check_connections ();
+ return &cp->pid;
}
/**
- * Check that we are aware of a connection from a neighboring peer.
+ * Iterate over all known peers.
*
- * @param peer Peer to the connection is with
- * @param c Connection that should be in the map with this peer.
+ * @param iter Iterator.
+ * @param cls Closure for @c iter.
*/
void
-GCP_check_connection (const struct CadetPeer *peer,
- const struct CadetConnection *c)
+GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
+ void *cls)
{
- GNUNET_assert (NULL != peer);
- GNUNET_assert (NULL != peer->connections);
- return; // ????
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multishortmap_contains_value (peer->connections,
- &GCC_get_id (c)->connection_of_tunnel,
- c));
+ GNUNET_CONTAINER_multipeermap_iterate (peers,
+ iter,
+ cls);
}
/**
- * Remove a connection from a neighboring peer.
+ * Count the number of known paths toward the peer.
*
- * @param peer Peer to remove connection from.
- * @param c Connection to remove.
+ * @param cp Peer to get path info.
+ * @return Number of known paths.
*/
-void
-GCP_remove_connection (struct CadetPeer *peer,
- const struct CadetConnection *c)
+unsigned int
+GCP_count_paths (const struct CadetPeer *cp)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Removing connection %s\n",
- GCC_2s (c));
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "from peer %s\n",
- GCP_2s (peer));
- if ( (NULL == peer) ||
- (NULL == peer->connections) )
- return;
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multishortmap_remove (peer->connections,
- &GCC_get_id (c)->connection_of_tunnel,
- c));
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Peer %s remains with %u connections.\n",
- GCP_2s (peer),
- GNUNET_CONTAINER_multishortmap_size (peer->connections));
+ return cp->num_paths;
}
/**
- * Start the DHT search for new paths towards the peer: we don't have
- * enough good connections.
+ * Iterate over the paths to a peer.
*
- * @param peer Destination peer.
+ * @param cp Peer to get path info.
+ * @param callback Function to call for every path.
+ * @param callback_cls Closure for @a callback.
+ * @return Number of iterated paths.
*/
-void
-GCP_start_search (struct CadetPeer *peer)
+unsigned int
+GCP_iterate_paths (struct CadetPeer *cp,
+ GCP_PathIterator callback,
+ void *callback_cls)
{
- const struct GNUNET_PeerIdentity *id;
- struct CadetTunnel *t = peer->tunnel;
-
- GCC_check_connections ();
- if (NULL != peer->search_h)
- {
- GNUNET_break (0);
- return;
- }
-
- if (NULL != peer->search_delayed)
- GCP_stop_search (peer);
-
- id = GNUNET_PEER_resolve2 (peer->id);
- peer->search_h = GCD_search (id, &search_handler, peer);
-
- if (NULL == t)
- {
- /* Why would we search for a peer with no tunnel towards it? */
- GNUNET_break (0);
- return;
- }
-
- if (CADET_TUNNEL_NEW == GCT_get_cstate (t)
- || 0 == GCT_count_any_connections (t))
- {
- GCT_change_cstate (t, CADET_TUNNEL_SEARCHING);
- }
- GCC_check_connections ();
-}
+ unsigned int ret = 0;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Iterating over paths to peer %s%s\n",
+ GCP_2s (cp),
+ (NULL == cp->core_mq) ? "" : " including direct link");
+ if (NULL != cp->core_mq)
+ {
+ struct CadetPeerPath *path;
-/**
- * Stop the DHT search for new paths towards the peer: we already have
- * enough good connections.
- *
- * @param peer Destination peer.
- */
-void
-GCP_stop_search (struct CadetPeer *peer)
-{
- GCC_check_connections ();
- if (NULL != peer->search_h)
- {
- GCD_search_stop (peer->search_h);
- peer->search_h = NULL;
- }
- if (NULL != peer->search_delayed)
+ path = GCPP_get_path_from_route (1,
+ &cp->pid);
+ ret++;
+ if (GNUNET_NO ==
+ callback (callback_cls,
+ path,
+ 0))
+ return ret;
+ }
+ for (unsigned int i=0;i<cp->path_dll_length;i++)
+ {
+ for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
+ NULL != pe;
+ pe = pe->next)
{
- GNUNET_SCHEDULER_cancel (peer->search_delayed);
- peer->search_delayed = NULL;
+ ret++;
+ if (GNUNET_NO ==
+ callback (callback_cls,
+ pe->path,
+ i))
+ return ret;
}
- GCC_check_connections ();
-}
-
-
-/**
- * Get the Full ID of a peer.
- *
- * @param peer Peer to get from.
- *
- * @return Full ID of peer.
- */
-const struct GNUNET_PeerIdentity *
-GCP_get_id (const struct CadetPeer *peer)
-{
- return GNUNET_PEER_resolve2 (peer->id);
+ }
+ return ret;
}
/**
- * Get the Short ID of a peer.
- *
- * @param peer Peer to get from.
+ * Iterate over the paths to @a cp where
+ * @a cp is at distance @a dist from us.
*
- * @return Short ID of peer.
+ * @param cp Peer to get path info.
+ * @param dist desired distance of @a cp to us on the path
+ * @param callback Function to call for every path.
+ * @param callback_cls Closure for @a callback.
+ * @return Number of iterated paths.
*/
-GNUNET_PEER_Id
-GCP_get_short_id (const struct CadetPeer *peer)
+unsigned int
+GCP_iterate_paths_at (struct CadetPeer *cp,
+ unsigned int dist,
+ GCP_PathIterator callback,
+ void *callback_cls)
{
- return peer->id;
-}
-
+ unsigned int ret = 0;
-/**
- * Set tunnel.
- *
- * If tunnel is NULL and there was a search active, stop it, as it's useless.
- *
- * @param peer Peer.
- * @param t Tunnel.
- */
-void
-GCP_set_tunnel (struct CadetPeer *peer, struct CadetTunnel *t)
-{
- peer->tunnel = t;
- if (NULL == t && GNUNET_YES == is_searching (peer))
- {
- GCP_stop_search (peer);
- }
+ if (dist >= cp->path_dll_length)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Asked to look for paths at distance %u, but maximum for me is < %u\n",
+ dist,
+ cp->path_dll_length);
+ return 0;
+ }
+ for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
+ NULL != pe;
+ pe = pe->next)
+ {
+ if (GNUNET_NO ==
+ callback (callback_cls,
+ pe->path,
+ dist))
+ return ret;
+ ret++;
+ }
+ return ret;
}
/**
* Get the tunnel towards a peer.
*
- * @param peer Peer to get from.
- *
+ * @param cp Peer to get from.
+ * @param create #GNUNET_YES to create a tunnel if we do not have one
* @return Tunnel towards peer.
*/
struct CadetTunnel *
-GCP_get_tunnel (const struct CadetPeer *peer)
+GCP_get_tunnel (struct CadetPeer *cp,
+ int create)
{
- if (NULL == peer)
- return NULL;
- return peer->tunnel;
+ if (NULL == cp)
+ return NULL;
+ if ( (NULL != cp->t) ||
+ (GNUNET_NO == create) )
+ return cp->t;
+ cp->t = GCT_create_tunnel (cp);
+ consider_peer_activate (cp);
+ return cp->t;
}
/**
- * Set the hello message.
+ * Hello offer was passed to the transport service. Mark it
+ * as done.
*
- * @param peer Peer whose message to set.
- * @param hello Hello message.
+ * @param cls the `struct CadetPeer` where the offer completed
*/
-void
-GCP_set_hello (struct CadetPeer *peer,
- const struct GNUNET_HELLO_Message *hello)
+static void
+hello_offer_done (void *cls)
{
- struct GNUNET_HELLO_Message *old;
- size_t size;
+ struct CadetPeer *cp = cls;
- GCC_check_connections ();
- LOG (GNUNET_ERROR_TYPE_DEBUG, "set hello for %s\n", GCP_2s (peer));
- if (NULL == hello)
- return;
-
- old = GCP_get_hello (peer);
- if (NULL == old)
- {
- size = GNUNET_HELLO_size (hello);
- peer->hello = GNUNET_malloc (size);
- GNUNET_memcpy (peer->hello, hello, size);
- }
- else
- {
- peer->hello = GNUNET_HELLO_merge (old, hello);
- GNUNET_free (old);
- }
- GCC_check_connections ();
+ cp->hello_offer = NULL;
}
/**
- * Get the hello message.
- *
- * @param peer Peer whose message to get.
+ * We got a HELLO for a @a peer, remember it, and possibly
+ * trigger adequate actions (like trying to connect).
*
- * @return Hello message.
+ * @param cp the peer we got a HELLO for
+ * @param hello the HELLO to remember
*/
-struct GNUNET_HELLO_Message *
-GCP_get_hello (struct CadetPeer *peer)
+void
+GCP_set_hello (struct CadetPeer *cp,
+ const struct GNUNET_HELLO_Message *hello)
{
- struct GNUNET_TIME_Absolute expiration;
- struct GNUNET_TIME_Relative remaining;
-
- if (NULL == peer->hello)
- return NULL;
+ struct GNUNET_HELLO_Message *mrg;
- 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;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Got %u byte HELLO for peer %s\n",
+ (unsigned int) GNUNET_HELLO_size (hello),
+ GCP_2s (cp));
+ if (NULL != cp->hello_offer)
+ {
+ GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
+ cp->hello_offer = NULL;
+ }
+ if (NULL != cp->hello)
+ {
+ mrg = GNUNET_HELLO_merge (hello,
+ cp->hello);
+ GNUNET_free (cp->hello);
+ cp->hello = mrg;
+ }
+ else
+ {
+ cp->hello = GNUNET_memdup (hello,
+ GNUNET_HELLO_size (hello));
+ }
+ cp->hello_offer
+ = GNUNET_TRANSPORT_offer_hello (cfg,
+ GNUNET_HELLO_get_header (cp->hello) ,
+ &hello_offer_done,
+ cp);
+ /* New HELLO means cp's destruction time may change... */
+ consider_peer_destroy (cp);
}
/**
- * Try to connect to a peer on TRANSPORT level.
+ * The tunnel to the given peer no longer exists, remove it from our
+ * data structures, and possibly clean up the peer itself.
*
- * @param peer Peer to whom to connect.
+ * @param cp the peer affected
+ * @param t the dead tunnel
*/
void
-GCP_try_connect (struct CadetPeer *peer)
+GCP_drop_tunnel (struct CadetPeer *cp,
+ struct CadetTunnel *t)
{
- struct GNUNET_HELLO_Message *hello;
- struct GNUNET_MessageHeader *mh;
-
- if (GNUNET_YES !=
- GNUNET_CONFIGURATION_get_value_yesno (cfg,
- "CADET",
- "DISABLE_TRY_CONNECT"))
- return;
- GCC_check_connections ();
- if (GNUNET_YES == GCP_is_neighbor (peer))
- return;
- hello = GCP_get_hello (peer);
- if (NULL == hello)
- return;
-
- mh = GNUNET_HELLO_get_header (hello);
- if (NULL != peer->hello_offer)
- {
- GNUNET_TRANSPORT_offer_hello_cancel (peer->hello_offer);
- peer->hello_offer = NULL;
- }
- peer->hello_offer = GNUNET_TRANSPORT_offer_hello (cfg,
- mh,
- &hello_offer_done,
- peer);
- if (NULL == peer->connectivity_suggestion)
- peer->connectivity_suggestion
- = GNUNET_ATS_connectivity_suggest (ats_ch,
- GCP_get_id (peer),
- 1); /* strength */
- GCC_check_connections ();
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Dropping tunnel %s to peer %s\n",
+ GCT_2s (t),
+ GCP_2s (cp));
+ GNUNET_assert (cp->t == t);
+ cp->t = NULL;
+ consider_peer_destroy (cp);
}
/**
- * Notify a peer that a link between two other peers is broken. If any path
- * used that link, eliminate it.
+ * Test if @a cp has a core-level connection
*
- * @param peer Peer affected by the change.
- * @param peer1 Peer whose link is broken.
- * @param peer2 Peer whose link is broken.
+ * @param cp peer to test
+ * @return #GNUNET_YES if @a cp has a core-level connection
*/
-void
-GCP_notify_broken_link (struct CadetPeer *peer,
- const struct GNUNET_PeerIdentity *peer1,
- const struct GNUNET_PeerIdentity *peer2)
+int
+GCP_has_core_connection (struct CadetPeer *cp)
{
- struct CadetPeerPath *iter;
- struct CadetPeerPath *next;
- unsigned int i;
- GNUNET_PEER_Id p1;
- GNUNET_PEER_Id p2;
-
- GCC_check_connections ();
- 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);
- }
- }
- }
- GCC_check_connections ();
+ return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
}
/**
- * Count the number of known paths toward the peer.
- *
- * @param peer Peer to get path info.
+ * Start message queue change notifications.
*
- * @return Number of known paths.
+ * @param cp peer to notify for
+ * @param cb function to call if mq becomes available or unavailable
+ * @param cb_cls closure for @a cb
+ * @return handle to cancel request
*/
-unsigned int
-GCP_count_paths (const struct CadetPeer *peer)
+struct GCP_MessageQueueManager *
+GCP_request_mq (struct CadetPeer *cp,
+ GCP_MessageQueueNotificationCallback cb,
+ void *cb_cls)
{
- struct CadetPeerPath *iter;
- unsigned int i;
+ struct GCP_MessageQueueManager *mqm;
- for (iter = peer->path_head, i = 0; NULL != iter; iter = iter->next)
- i++;
-
- return i;
+ mqm = GNUNET_new (struct GCP_MessageQueueManager);
+ mqm->cb = cb;
+ mqm->cb_cls = cb_cls;
+ mqm->cp = cp;
+ GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
+ cp->mqm_tail,
+ mqm);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating MQM %p for peer %s\n",
+ mqm,
+ GCP_2s (cp));
+ if (NULL != cp->core_mq)
+ cb (cb_cls,
+ GNUNET_YES);
+ return mqm;
}
/**
- * Iterate over the paths to a peer.
+ * Stops message queue change notifications.
*
- * @param peer Peer to get path info.
- * @param callback Function to call for every path.
- * @param cls Closure for @a callback.
- *
- * @return Number of iterated paths.
+ * @param mqm handle matching request to cancel
+ * @param last_env final message to transmit, or NULL
*/
-unsigned int
-GCP_iterate_paths (struct CadetPeer *peer,
- GCP_path_iterator callback,
- void *cls)
-{
- struct CadetPeerPath *iter;
- unsigned int i;
-
- for (iter = peer->path_head, i = 0; NULL != iter; iter = iter->next)
+void
+GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
+ struct GNUNET_MQ_Envelope *last_env)
+{
+ struct CadetPeer *cp = mqm->cp;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Destroying MQM %p for peer %s%s\n",
+ mqm,
+ GCP_2s (cp),
+ (NULL == last_env) ? "" : " with last ditch transmission");
+ if (NULL != mqm->env)
+ GNUNET_MQ_discard (mqm->env);
+ if (NULL != last_env)
+ {
+ if (NULL != cp->core_mq)
{
- i++;
- if (GNUNET_YES != callback (cls, peer, iter))
- break;
+ GNUNET_MQ_notify_sent (last_env,
+ &mqm_send_done,
+ cp);
+ GNUNET_MQ_send (cp->core_mq,
+ last_env);
}
-
- return i;
+ else
+ {
+ GNUNET_MQ_discard (last_env);
+ }
+ }
+ if (cp->mqm_ready_ptr == mqm)
+ cp->mqm_ready_ptr = mqm->next;
+ GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
+ cp->mqm_tail,
+ mqm);
+ GNUNET_free (mqm);
}
/**
- * Iterate all known peers.
+ * Send the message in @a env to @a cp, overriding queueing logic.
+ * This function should only be used to send error messages outside
+ * of flow and congestion control, similar to ICMP. Note that
+ * the envelope may be silently discarded as well.
*
- * @param iter Iterator.
- * @param cls Closure for @c iter.
+ * @param cp peer to send the message to
+ * @param env envelope with the message to send
*/
void
-GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
- void *cls)
+GCP_send_ooo (struct CadetPeer *cp,
+ struct GNUNET_MQ_Envelope *env)
{
- GCC_check_connections ();
- GNUNET_CONTAINER_multipeermap_iterate (peers,
- iter,
- cls);
- GCC_check_connections ();
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending message to %s out of management\n",
+ GCP_2s (cp));
+ if (NULL == cp->core_mq)
+ {
+ GNUNET_MQ_discard (env);
+ return;
+ }
+ GNUNET_MQ_notify_sent (env,
+ &mqm_send_done,
+ cp);
+ GNUNET_MQ_send (cp->core_mq,
+ env);
}
-/**
- * Get the static string for a peer ID.
- *
- * @param peer Peer.
- *
- * @return Static string for it's ID.
- */
-const char *
-GCP_2s (const struct CadetPeer *peer)
-{
- if (NULL == peer)
- return "(NULL)";
- return GNUNET_i2s (GNUNET_PEER_resolve2 (peer->id));
-}
-/* end of gnunet-service-cadet_peer.c */
+/* end of gnunet-service-cadet-new_peer.c */
diff --git a/src/cadet/gnunet-service-cadet_peer.h b/src/cadet/gnunet-service-cadet_peer.h
index 1e206e10f1..a2a6c6a92a 100644
--- a/src/cadet/gnunet-service-cadet_peer.h
+++ b/src/cadet/gnunet-service-cadet_peer.h
@@ -1,6 +1,7 @@
+
/*
This file is part of GNUnet.
- Copyright (C) 2013 GNUnet e.V.
+ Copyright (C) 2001-2017 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
@@ -19,465 +20,375 @@
*/
/**
- * @file cadet/gnunet-service-cadet_peer.h
- * @brief cadet service; dealing with remote peers
+ * @file cadet/gnunet-service-cadet-new_peer.h
+ * @brief Information we track per peer.
* @author Bartlomiej Polot
- *
- * All functions in this file should use the prefix GMP (Gnunet Cadet Peer)
+ * @author Christian Grothoff
*/
-
#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"
-#include "cadet_path.h"
-
-/**
- * Struct containing all information regarding a given peer
- */
-struct CadetPeer;
+#include "gnunet-service-cadet.h"
+#include "gnunet_hello_lib.h"
-/**
- * Handle to queued messages on a peer level.
- */
-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 fwd Was this a FWD going message?
- * @param sent Was it really sent? (Could have been canceled)
- * @param type Type of message sent.
- * @param payload_type Type of payload, if applicable.
- * @param pid Message ID, or 0 if not applicable (create, destroy, etc).
- * @param size Size of the message.
- * @param wait Time spent waiting for core (only the time for THIS message)
- */
-typedef void
-(*GCP_sent) (void *cls,
- struct CadetConnection *c,
- int fwd,
- int sent,
- uint16_t type,
- uint16_t payload_type,
- struct CadetEncryptedMessageIdentifier pid,
- size_t size,
- struct GNUNET_TIME_Relative wait);
/**
- * Peer path iterator.
+ * Get the static string for a peer ID.
*
- * @param cls Closure.
- * @param peer Peer this path is towards.
- * @param path Path itself
- * @return #GNUNET_YES if should keep iterating.
- * #GNUNET_NO otherwise.
- */
-typedef int
-(*GCP_path_iterator) (void *cls,
- struct CadetPeer *peer,
- struct CadetPeerPath *path);
-
-
-/******************************************************************************/
-/******************************** API ***********************************/
-/******************************************************************************/
-
-/**
- * Initialize peer subsystem.
+ * @param peer Peer.
*
- * @param c Configuration.
- */
-void
-GCP_init (const struct GNUNET_CONFIGURATION_Handle *c);
-
-/**
- * Shut down the peer subsystem.
+ * @return Static string for it's ID.
*/
-void
-GCP_shutdown (void);
+const char *
+GCP_2s (const struct CadetPeer *peer);
/**
- * Retrieve the CadetPeer stucture associated with the peer. Optionally create
- * one and insert it in the appropriate structures if the peer is not known yet.
+ * Retrieve the CadetPeer stucture associated with the
+ * peer. Optionally create one and insert it in the appropriate
+ * structures if the peer is not known yet.
*
* @param peer_id Full identity of the peer.
* @param create #GNUNET_YES if a new peer should be created if unknown.
- * #GNUNET_NO otherwise.
- *
+ * #GNUNET_NO to return NULL if peer is unknown.
* @return Existing or newly created peer structure.
* NULL if unknown and not requested @a create
*/
struct CadetPeer *
-GCP_get (const struct GNUNET_PeerIdentity *peer_id, int create);
+GCP_get (const struct GNUNET_PeerIdentity *peer_id,
+ int create);
/**
- * Retrieve the CadetPeer stucture associated with the peer. Optionally create
- * one and insert it in the appropriate structures if the peer is not known yet.
- *
- * @param peer Short identity of the peer.
- * @param create #GNUNET_YES if a new peer should be created if unknown.
- * #GNUNET_NO otherwise.
+ * Calculate how desirable a path is for @a cp if
+ * @a cp is at offset @a off in the path.
*
- * @return Existing or newly created peer structure.
- * NULL if unknown and not requested @a create
+ * @param cp a peer reachable via a path
+ * @param off offset of @a cp in a path
+ * @return score how useful a path is to reach @a cp,
+ * positive scores mean path is more desirable
*/
-struct CadetPeer *
-GCP_get_short (const GNUNET_PEER_Id peer, int create);
-
+double
+GCP_get_desirability_of_path (struct CadetPeer *cp,
+ unsigned int off);
-/**
- * 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
-GCP_connect (struct CadetPeer *peer);
/**
- * @brief Send a message to another peer (using CORE).
+ * Obtain the peer identity for a `struct CadetPeer`.
*
- * @param peer Peer towards which to queue the message.
- * @param message Message to send.
- * @param payload_type Type of the message's payload, for debug messages.
- * 0 if the message is a retransmission (unknown payload).
- * UINT16_MAX if the message does not have payload.
- * @param payload_id ID of the payload (MID, ACK #, etc)
- * @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 sent the message.
- * @param cont_cls Closure for @c cont.
+ * @param cp our peer handle
+ * @return the peer identity
*/
-struct CadetPeerQueue *
-GCP_send (struct CadetPeer *peer,
- const struct GNUNET_MessageHeader *message,
- uint16_t payload_type,
- struct CadetEncryptedMessageIdentifier payload_id,
- struct CadetConnection *c,
- int fwd,
- GCP_sent cont,
- void *cont_cls);
+const struct GNUNET_PeerIdentity *
+GCP_get_id (struct CadetPeer *cp);
-/**
- * Cancel sending a message. Message must have been sent with
- * #GCP_send before. May not be called after the notify sent
- * callback has been called.
- *
- * It does NOT call the continuation given to #GCP_send.
- *
- * @param q Queue handle to cancel
- */
-void
-GCP_send_cancel (struct CadetPeerQueue *q);
/**
- * Set tunnel.
+ * Iterate over all known peers.
*
- * @param peer Peer.
- * @param t Tunnel.
+ * @param iter Iterator.
+ * @param cls Closure for @c iter.
*/
void
-GCP_set_tunnel (struct CadetPeer *peer, struct CadetTunnel *t);
+GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
+ void *cls);
/**
- * Check whether there is a direct (core level) connection to peer.
- *
- * @param peer Peer to check.
+ * Count the number of known paths toward the peer.
*
- * @return #GNUNET_YES if there is a direct connection.
+ * @param cp Peer to get path info.
+ * @return Number of known paths.
*/
-int
-GCP_is_neighbor (const struct CadetPeer *peer);
+unsigned int
+GCP_count_paths (const struct CadetPeer *cp);
/**
- * 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.
+ * Drop all paths owned by this peer, and do not
+ * allow new ones to be added: We are shutting down.
*
- * @param peer Peer towards which to create the tunnel.
+ * @param cp peer to drop paths to
*/
void
-GCP_add_tunnel (struct CadetPeer *peer);
+GCP_drop_owned_paths (struct CadetPeer *cp);
/**
- * 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.
+ * Peer path iterator.
*
- * @param peer Peer to add connection to.
- * @param c Connection to add.
- * @param pred #GNUNET_YES if we are predecessor, #GNUNET_NO if we are successor
+ * @param cls Closure.
+ * @param path Path itself
+ * @param off offset of the target peer in @a path
+ * @return #GNUNET_YES if should keep iterating.
+ * #GNUNET_NO otherwise.
*/
-void
-GCP_add_connection (struct CadetPeer *peer,
- struct CadetConnection *c,
- int pred);
+typedef int
+(*GCP_PathIterator) (void *cls,
+ struct CadetPeerPath *path,
+ unsigned int off);
/**
- * 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?
+ * Iterate over the paths to a peer.
*
- * @return path if path was taken, pointer to existing duplicate if exists
- * NULL on error.
+ * @param cp Peer to get path info.
+ * @param callback Function to call for every path.
+ * @param callback_cls Closure for @a callback.
+ * @return Number of iterated paths.
*/
-struct CadetPeerPath *
-GCP_add_path (struct CadetPeer *peer,
- struct CadetPeerPath *p,
- int trusted);
+unsigned int
+GCP_iterate_paths (struct CadetPeer *cp,
+ GCP_PathIterator callback,
+ void *callback_cls);
/**
- * 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.
+ * Iterate over the paths to @a peer where
+ * @a peer is at distance @a dist from us.
*
- * @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.
+ * @param cp Peer to get path info.
+ * @param dist desired distance of @a peer to us on the path
+ * @param callback Function to call for every path.
+ * @param callback_cls Closure for @a callback.
+ * @return Number of iterated paths.
*/
-struct CadetPeerPath *
-GCP_add_path_to_origin (struct CadetPeer *peer,
- struct CadetPeerPath *path,
- int trusted);
+unsigned int
+GCP_iterate_paths_at (struct CadetPeer *cp,
+ unsigned int dist,
+ GCP_PathIterator callback,
+ void *callback_cls);
+
/**
- * Adds a path to the info of all the peers in the path
+ * Remove an entry from the DLL of all of the paths that this peer is on.
*
- * @param p Path to process.
- * @param confirmed Whether we know if the path works or not.
+ * @param cp peer to modify
+ * @param entry an entry on a path
+ * @param off offset of this peer on the path
*/
void
-GCP_add_path_to_all (const struct CadetPeerPath *p, int confirmed);
+GCP_path_entry_remove (struct CadetPeer *cp,
+ struct CadetPeerPathEntry *entry,
+ unsigned int off);
/**
- * Remove any path to the peer that has the extact same peers as the one given.
+ * Add an entry to the DLL of all of the paths that this peer is on.
*
- * @param peer Peer to remove the path from.
- * @param path Path to remove. Is always destroyed .
+ * @param cp peer to modify
+ * @param entry an entry on a path
+ * @param off offset of this peer on the path
*/
void
-GCP_remove_path (struct CadetPeer *peer,
- struct CadetPeerPath *path);
+GCP_path_entry_add (struct CadetPeer *cp,
+ struct CadetPeerPathEntry *entry,
+ unsigned int off);
/**
- * Check that we are aware of a connection from a neighboring peer.
+ * Get the tunnel towards a peer.
*
- * @param peer Peer to the connection is with
- * @param c Connection that should be in the map with this peer.
+ * @param cp Peer to get from.
+ * @param create #GNUNET_YES to create a tunnel if we do not have one
+ * @return Tunnel towards peer.
*/
-void
-GCP_check_connection (const struct CadetPeer *peer,
- const struct CadetConnection *c);
+struct CadetTunnel *
+GCP_get_tunnel (struct CadetPeer *cp,
+ int create);
/**
- * Remove a connection from a neighboring peer.
+ * The tunnel to the given peer no longer exists, remove it from our
+ * data structures, and possibly clean up the peer itself.
*
- * @param peer Peer to remove connection from.
- * @param c Connection to remove.
+ * @param cp the peer affected
+ * @param t the dead tunnel
*/
void
-GCP_remove_connection (struct CadetPeer *peer,
- const struct CadetConnection *c);
+GCP_drop_tunnel (struct CadetPeer *cp,
+ struct CadetTunnel *t);
/**
- * Start the DHT search for new paths towards the peer: we don't have
- * enough good connections.
+ * Try adding a @a path to this @a cp. If the peer already
+ * has plenty of paths, return NULL.
*
- * @param peer Destination peer.
+ * @param cp peer to which the @a path leads to
+ * @param path a path looking for an owner; may not be fully initialized yet!
+ * @param off offset of @a cp in @a path
+ * @param force for attaching the path
+ * @return NULL if this peer does not care to become a new owner,
+ * otherwise the node in the peer's path heap for the @a path.
*/
-void
-GCP_start_search (struct CadetPeer *peer);
+struct GNUNET_CONTAINER_HeapNode *
+GCP_attach_path (struct CadetPeer *cp,
+ struct CadetPeerPath *path,
+ unsigned int off,
+ int force);
/**
- * Stop the DHT search for new paths towards the peer: we already have
- * enough good connections.
+ * This peer can no longer own @a path as the path
+ * has been extended and a peer further down the line
+ * is now the new owner.
*
- * @param peer Destination peer.
+ * @param cp old owner of the @a path
+ * @param path path where the ownership is lost
+ * @param hn note in @a cp's path heap that must be deleted
*/
void
-GCP_stop_search (struct CadetPeer *peer);
+GCP_detach_path (struct CadetPeer *cp,
+ struct CadetPeerPath *path,
+ struct GNUNET_CONTAINER_HeapNode *hn);
/**
- * Get the Full ID of a peer.
- *
- * @param peer Peer to get from.
+ * Add a @a connection to this @a cp.
*
- * @return Full ID of peer.
+ * @param cp peer via which the @a connection goes
+ * @param cc the connection to add
*/
-const struct GNUNET_PeerIdentity *
-GCP_get_id (const struct CadetPeer *peer);
+void
+GCP_add_connection (struct CadetPeer *cp,
+ struct CadetConnection *cc);
/**
- * Get the Short ID of a peer.
+ * Remove a @a connection that went via this @a cp.
*
- * @param peer Peer to get from.
- *
- * @return Short ID of peer.
+ * @param cp peer via which the @a connection went
+ * @param cc the connection to remove
*/
-GNUNET_PEER_Id
-GCP_get_short_id (const struct CadetPeer *peer);
+void
+GCP_remove_connection (struct CadetPeer *cp,
+ struct CadetConnection *cc);
/**
- * Get the tunnel towards a peer.
- *
- * @param peer Peer to get from.
+ * We got a HELLO for a @a cp, remember it, and possibly
+ * trigger adequate actions (like trying to connect).
*
- * @return Tunnel towards peer.
+ * @param cp the peer we got a HELLO for
+ * @param hello the HELLO to remember
*/
-struct CadetTunnel *
-GCP_get_tunnel (const struct CadetPeer *peer);
+void
+GCP_set_hello (struct CadetPeer *cp,
+ const struct GNUNET_HELLO_Message *hello);
/**
- * Set the hello message.
- *
- * @param peer Peer whose message to set.
- * @param hello Hello message.
+ * Clean up all entries about all peers.
+ * Must only be called after all tunnels, CORE-connections and
+ * connections are down.
*/
void
-GCP_set_hello (struct CadetPeer *peer,
- const struct GNUNET_HELLO_Message *hello);
+GCP_destroy_all_peers (void);
/**
- * Get the hello message.
- *
- * @param peer Peer whose message to get.
+ * Data structure used to track whom we have to notify about changes
+ * in our ability to transmit to a given peer.
*
- * @return Hello message.
+ * All queue managers will be given equal chance for sending messages
+ * to @a cp. This construct this guarantees fairness for access to @a
+ * cp among the different message queues. Each connection or route
+ * will have its respective message queue managers for each direction.
*/
-struct GNUNET_HELLO_Message *
-GCP_get_hello (struct CadetPeer *peer);
+struct GCP_MessageQueueManager;
/**
- * Try to connect to a peer on TRANSPORT level.
+ * Function to call with updated message queue object.
*
- * @param peer Peer to whom to connect.
+ * @param cls closure
+ * @param available #GNUNET_YES if sending is now possible,
+ * #GNUNET_NO if sending is no longer possible
+ * #GNUNET_SYSERR if sending is no longer possible
+ * and the last envelope was discarded
*/
-void
-GCP_try_connect (struct CadetPeer *peer);
+typedef void
+(*GCP_MessageQueueNotificationCallback)(void *cls,
+ int available);
+
/**
- * Notify a peer that a link between two other peers is broken. If any path
- * used that link, eliminate it.
+ * Start message queue change notifications. Will create a new slot
+ * to manage the message queue to the given @a cp.
*
- * @param peer Peer affected by the change.
- * @param peer1 Peer whose link is broken.
- * @param peer2 Peer whose link is broken.
+ * @param cp peer to notify for
+ * @param cb function to call if mq becomes available or unavailable
+ * @param cb_cls closure for @a cb
+ * @return handle to cancel request
*/
-void
-GCP_notify_broken_link (struct CadetPeer *peer,
- const struct GNUNET_PeerIdentity *peer1,
- const struct GNUNET_PeerIdentity *peer2);
+struct GCP_MessageQueueManager *
+GCP_request_mq (struct CadetPeer *cp,
+ GCP_MessageQueueNotificationCallback cb,
+ void *cb_cls);
/**
- * Count the number of known paths toward the peer.
- *
- * @param peer Peer to get path info.
+ * Test if @a cp has a core-level connection
*
- * @return Number of known paths.
+ * @param cp peer to test
+ * @return #GNUNET_YES if @a cp has a core-level connection
*/
-unsigned int
-GCP_count_paths (const struct CadetPeer *peer);
+int
+GCP_has_core_connection (struct CadetPeer *cp);
+
/**
- * Iterate over the paths to a peer.
- *
- * @param peer Peer to get path info.
- * @param callback Function to call for every path.
- * @param cls Closure for @a callback.
+ * Send the message in @a env via a @a mqm. Must only be called at
+ * most once after the respective
+ * #GCP_MessageQueueNotificationCallback was called with `available`
+ * set to #GNUNET_YES, and not after the callback was called with
+ * `available` set to #GNUNET_NO or #GNUNET_SYSERR.
*
- * @return Number of iterated paths.
+ * @param mqm message queue manager for the transmission
+ * @param env envelope with the message to send; must NOT
+ * yet have a #GNUNET_MQ_notify_sent() callback attached to it
*/
-unsigned int
-GCP_iterate_paths (struct CadetPeer *peer,
- GCP_path_iterator callback,
- void *cls);
+void
+GCP_send (struct GCP_MessageQueueManager *mqm,
+ struct GNUNET_MQ_Envelope *env);
/**
- * Iterate all known peers.
+ * Send the message in @a env to @a cp, overriding queueing logic.
+ * This function should only be used to send error messages outside
+ * of flow and congestion control, similar to ICMP. Note that
+ * the envelope may be silently discarded as well.
*
- * @param iter Iterator.
- * @param cls Closure for @c iter.
+ * @param cp peer to send the message to
+ * @param env envelope with the message to send
*/
void
-GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
- void *cls);
+GCP_send_ooo (struct CadetPeer *cp,
+ struct GNUNET_MQ_Envelope *env);
/**
- * Get the static string for a peer ID.
- *
- * @param peer Peer.
+ * Stops message queue change notifications and sends a last message.
+ * In practice, this is implemented by sending that @a last_env
+ * message immediately (if any), ignoring queue order.
*
- * @return Static string for it's ID.
+ * @param mqm handle matching request to cancel
+ * @param last_env final message to transmit, or NULL
*/
-const char *
-GCP_2s (const struct CadetPeer *peer);
+void
+GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
+ struct GNUNET_MQ_Envelope *last_env);
/**
- * Log all kinds of info about a peer.
+ * Set the message queue to @a mq for peer @a cp and notify watchers.
*
- * @param peer Peer.
+ * @param cp peer to modify
+ * @param mq message queue to set (can be NULL)
*/
void
-GCP_debug (const struct CadetPeer *p,
- enum GNUNET_ErrorType level);
-
+GCP_set_mq (struct CadetPeer *cp,
+ struct GNUNET_MQ_Handle *mq);
-#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
deleted file mode 100644
index a94e8f4ffe..0000000000
--- a/src/cadet/gnunet-service-cadet_tunnel.c
+++ /dev/null
@@ -1,3501 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2013, 2017 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/gnunet-service-cadet_tunnel.c
- * @brief logical links between CADET clients
- * @author Bartlomiej Polot
- */
-#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 LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-tun",__VA_ARGS__)
-
-#define REKEY_WAIT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5)
-
-#if !defined(GNUNET_CULL_LOGGING)
- #define DUMP_KEYS_TO_STDERR GNUNET_YES
-#else
- #define DUMP_KEYS_TO_STDERR GNUNET_NO
-#endif
-
-#define MIN_TUNNEL_BUFFER 8
-#define MAX_TUNNEL_BUFFER 64
-#define MAX_SKIPPED_KEYS 64
-#define MAX_KEY_GAP 256
-#define AX_HEADER_SIZE (sizeof (uint32_t) * 2\
- + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey))
-
-/******************************************************************************/
-/******************************** STRUCTS **********************************/
-/******************************************************************************/
-
-struct CadetTChannel
-{
- struct CadetTChannel *next;
- struct CadetTChannel *prev;
- struct CadetChannel *ch;
-};
-
-
-/**
- * Entry in list of connections used by tunnel, with 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;
-};
-
-
-/**
- * Struct to old keys for skipped messages while advancing the Axolotl ratchet.
- */
-struct CadetTunnelSkippedKey
-{
- /**
- * DLL next.
- */
- struct CadetTunnelSkippedKey *next;
-
- /**
- * DLL prev.
- */
- struct CadetTunnelSkippedKey *prev;
-
- /**
- * When was this key stored (for timeout).
- */
- struct GNUNET_TIME_Absolute timestamp;
-
- /**
- * Header key.
- */
- struct GNUNET_CRYPTO_SymmetricSessionKey HK;
-
- /**
- * Message key.
- */
- struct GNUNET_CRYPTO_SymmetricSessionKey MK;
-
- /**
- * Key number for a given HK.
- */
- unsigned int Kn;
-};
-
-
-/**
- * Axolotl data, according to https://github.com/trevp/axolotl/wiki .
- */
-struct CadetTunnelAxolotl
-{
- /**
- * A (double linked) list of stored message keys and associated header keys
- * for "skipped" messages, i.e. messages that have not been
- * received despite the reception of more recent messages, (head).
- */
- struct CadetTunnelSkippedKey *skipped_head;
-
- /**
- * Skipped messages' keys DLL, tail.
- */
- struct CadetTunnelSkippedKey *skipped_tail;
-
- /**
- * Elements in @a skipped_head <-> @a skipped_tail.
- */
- unsigned int skipped;
-
- /**
- * 32-byte root key which gets updated by DH ratchet.
- */
- struct GNUNET_CRYPTO_SymmetricSessionKey RK;
-
- /**
- * 32-byte header key (send).
- */
- struct GNUNET_CRYPTO_SymmetricSessionKey HKs;
-
- /**
- * 32-byte header key (recv)
- */
- struct GNUNET_CRYPTO_SymmetricSessionKey HKr;
-
- /**
- * 32-byte next header key (send).
- */
- struct GNUNET_CRYPTO_SymmetricSessionKey NHKs;
-
- /**
- * 32-byte next header key (recv).
- */
- struct GNUNET_CRYPTO_SymmetricSessionKey NHKr;
-
- /**
- * 32-byte chain keys (used for forward-secrecy updating, send).
- */
- struct GNUNET_CRYPTO_SymmetricSessionKey CKs;
-
- /**
- * 32-byte chain keys (used for forward-secrecy updating, recv).
- */
- struct GNUNET_CRYPTO_SymmetricSessionKey CKr;
-
- /**
- * ECDH for key exchange (A0 / B0).
- */
- struct GNUNET_CRYPTO_EcdhePrivateKey *kx_0;
-
- /**
- * ECDH Ratchet key (send).
- */
- struct GNUNET_CRYPTO_EcdhePrivateKey *DHRs;
-
- /**
- * ECDH Ratchet key (recv).
- */
- struct GNUNET_CRYPTO_EcdhePublicKey DHRr;
-
- /**
- * Message number (reset to 0 with each new ratchet, next message to send).
- */
- uint32_t Ns;
-
- /**
- * Message number (reset to 0 with each new ratchet, next message to recv).
- */
- uint32_t Nr;
-
- /**
- * Previous message numbers (# of msgs sent under prev ratchet)
- */
- uint32_t PNs;
-
- /**
- * True (#GNUNET_YES) if we have to send a new ratchet key in next msg.
- */
- int ratchet_flag;
-
- /**
- * Number of messages recieved since our last ratchet advance.
- * - If this counter = 0, we cannot send a new ratchet key in next msg.
- * - If this counter > 0, we can (but don't yet have to) send a new key.
- */
- unsigned int ratchet_allowed;
-
- /**
- * Number of messages recieved since our last ratchet advance.
- * - If this counter = 0, we cannot send a new ratchet key in next msg.
- * - If this counter > 0, we can (but don't yet have to) send a new key.
- */
- unsigned int ratchet_counter;
-
- /**
- * When does this ratchet expire and a new one is triggered.
- */
- struct GNUNET_TIME_Absolute ratchet_expiration;
-};
-
-
-/**
- * Struct containing all information regarding a tunnel to a peer.
- */
-struct CadetTunnel
-{
- /**
- * Endpoint of the tunnel.
- */
- struct CadetPeer *peer;
-
- /**
- * Axolotl info.
- */
- struct CadetTunnelAxolotl *ax;
-
- /**
- * State of the tunnel connectivity.
- */
- enum CadetTunnelCState cstate;
-
- /**
- * State of the tunnel encryption.
- */
- enum CadetTunnelEState estate;
-
- /**
- * Peer's ephemeral key, to recreate @c e_key and @c d_key when own ephemeral
- * key changes.
- */
- struct GNUNET_CRYPTO_EcdhePublicKey peers_ephemeral_key;
-
- /**
- * Encryption ("our") key. It is only "confirmed" if kx_ctx is NULL.
- */
- struct GNUNET_CRYPTO_SymmetricSessionKey e_key;
-
- /**
- * Decryption ("their") key. It is only "confirmed" if kx_ctx is NULL.
- */
- struct GNUNET_CRYPTO_SymmetricSessionKey d_key;
-
- /**
- * Task to start the rekey process.
- */
- struct GNUNET_SCHEDULER_Task *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.
- */
- struct GNUNET_CADET_ChannelTunnelNumber next_ctn;
-
- /**
- * Destroy flag: if true, destroy on last message.
- */
- struct GNUNET_SCHEDULER_Task * destroy_task;
-
- /**
- * Queued messages, to transmit once tunnel gets connected.
- */
- struct CadetTunnelDelayed *tq_head;
- struct CadetTunnelDelayed *tq_tail;
-
- /**
- * Task to trim connections if too many are present.
- */
- struct GNUNET_SCHEDULER_Task * trim_connections_task;
-
- /**
- * Ephemeral message in the queue (to avoid queueing more than one).
- */
- struct CadetConnectionQueue *ephm_h;
-
- /**
- * Pong message in the queue.
- */
- struct CadetConnectionQueue *pong_h;
-};
-
-
-/**
- * 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 CadetTunnel *t;
-
- /**
- * Tunnel queue given to the channel to cancel request. Update on send_queued.
- */
- struct CadetTunnelQueue *tq;
-
- /**
- * Message to send.
- */
- /* struct GNUNET_MessageHeader *msg; */
-};
-
-
-/**
- * Handle for messages queued but not yet sent.
- */
-struct CadetTunnelQueue
-{
- /**
- * 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.
- */
- GCT_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;
-
-/**
- * Own Peer ID private key.
- */
-const static struct GNUNET_CRYPTO_EddsaPrivateKey *id_key;
-
-
-/******************************** AXOLOTL ************************************/
-
-/**
- * How many messages are needed to trigger a ratchet advance.
- */
-static unsigned long long ratchet_messages;
-
-/**
- * How long until we trigger a ratched advance.
- */
-static struct GNUNET_TIME_Relative ratchet_time;
-
-
-/******************************************************************************/
-/******************************** STATIC ***********************************/
-/******************************************************************************/
-
-/**
- * Get string description for tunnel connectivity state.
- *
- * @param cs Tunnel state.
- *
- * @return String representation.
- */
-static const char *
-cstate2s (enum CadetTunnelCState cs)
-{
- static char buf[32];
-
- switch (cs)
- {
- case CADET_TUNNEL_NEW:
- return "CADET_TUNNEL_NEW";
- case CADET_TUNNEL_SEARCHING:
- return "CADET_TUNNEL_SEARCHING";
- case CADET_TUNNEL_WAITING:
- return "CADET_TUNNEL_WAITING";
- case CADET_TUNNEL_READY:
- return "CADET_TUNNEL_READY";
- case CADET_TUNNEL_SHUTDOWN:
- return "CADET_TUNNEL_SHUTDOWN";
- 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 CadetTunnelEState es)
-{
- static char buf[32];
-
- switch (es)
- {
- case CADET_TUNNEL_KEY_UNINITIALIZED:
- return "CADET_TUNNEL_KEY_UNINITIALIZED";
- case CADET_TUNNEL_KEY_AX_SENT:
- return "CADET_TUNNEL_KEY_AX_SENT";
- case CADET_TUNNEL_KEY_AX_AUTH_SENT:
- return "CADET_TUNNEL_KEY_AX_AUTH_SENT";
- case CADET_TUNNEL_KEY_OK:
- return "CADET_TUNNEL_KEY_OK";
- case CADET_TUNNEL_KEY_REKEY:
- return "CADET_TUNNEL_KEY_REKEY";
- 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 CadetTunnel *t)
-{
- int ready;
- int conn_ok;
- int enc_ok;
-
- conn_ok = CADET_TUNNEL_READY == t->cstate;
- enc_ok = CADET_TUNNEL_KEY_OK == t->estate
- || CADET_TUNNEL_KEY_REKEY == t->estate
- || CADET_TUNNEL_KEY_AX_AUTH_SENT == t->estate;
- ready = conn_ok && enc_ok;
- ready = ready || GCT_is_loopback (t);
- return ready;
-}
-
-
-/**
- * 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 incoming, is terminal in the FWD direction and fwd is YES */
- fwd = GCCH_is_terminal (tch->ch, GNUNET_YES);
-
- return GCCH_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 = GCCH_is_origin (tch->ch, GNUNET_YES);
-
- return GCCH_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 = GCC_is_origin (tc->c, GNUNET_YES);
-
- return GCC_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 = GCC_is_origin (tc->c, GNUNET_YES);
-
- return GCC_get_allowed (tc->c, fwd);
-}
-
-
-/**
- * Create a new Axolotl ephemeral (ratchet) key.
- *
- * @param t Tunnel.
- */
-static void
-new_ephemeral (struct CadetTunnel *t)
-{
- GNUNET_free_non_null (t->ax->DHRs);
- t->ax->DHRs = GNUNET_CRYPTO_ecdhe_key_create();
- #if DUMP_KEYS_TO_STDERR
- {
- struct GNUNET_CRYPTO_EcdhePublicKey pub;
- GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->DHRs, &pub);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " new DHRs generated: pub %s\n",
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &pub));
- }
- #endif
-}
-
-
-/**
- * Calculate HMAC.
- *
- * @param plaintext Content to HMAC.
- * @param size Size of @c plaintext.
- * @param iv Initialization vector for the message.
- * @param key Key to use.
- * @param hmac[out] Destination to store the HMAC.
- */
-static void
-t_hmac (const void *plaintext, size_t size,
- uint32_t iv, const struct GNUNET_CRYPTO_SymmetricSessionKey *key,
- struct GNUNET_ShortHashCode *hmac)
-{
- static const char ctx[] = "cadet authentication key";
- struct GNUNET_CRYPTO_AuthKey auth_key;
- struct GNUNET_HashCode hash;
-
-#if DUMP_KEYS_TO_STDERR
- LOG (GNUNET_ERROR_TYPE_INFO, " HMAC %u bytes with key %s\n", size,
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) key));
-#endif
- GNUNET_CRYPTO_hmac_derive_key (&auth_key, key,
- &iv, sizeof (iv),
- key, sizeof (*key),
- ctx, sizeof (ctx),
- NULL);
- /* Two step: CADET_Hash is only 256 bits, HashCode is 512. */
- GNUNET_CRYPTO_hmac (&auth_key, plaintext, size, &hash);
- GNUNET_memcpy (hmac, &hash, sizeof (*hmac));
-}
-
-
-/**
- * Perform a HMAC.
- *
- * @param key Key to use.
- * @param hash[out] Resulting HMAC.
- * @param source Source key material (data to HMAC).
- * @param len Length of @a source.
- */
-static void
-t_ax_hmac_hash (struct GNUNET_CRYPTO_SymmetricSessionKey *key,
- struct GNUNET_HashCode *hash,
- void *source, unsigned int len)
-{
- static const char ctx[] = "axolotl HMAC-HASH";
- struct GNUNET_CRYPTO_AuthKey auth_key;
-
- GNUNET_CRYPTO_hmac_derive_key (&auth_key, key,
- ctx, sizeof (ctx),
- NULL);
- GNUNET_CRYPTO_hmac (&auth_key, source, len, hash);
-}
-
-
-/**
- * Derive a key from a HMAC-HASH.
- *
- * @param key Key to use for the HMAC.
- * @param out Key to generate.
- * @param source Source key material (data to HMAC).
- * @param len Length of @a source.
- */
-static void
-t_hmac_derive_key (struct GNUNET_CRYPTO_SymmetricSessionKey *key,
- struct GNUNET_CRYPTO_SymmetricSessionKey *out,
- void *source, unsigned int len)
-{
- static const char ctx[] = "axolotl derive key";
- struct GNUNET_HashCode h;
-
- t_ax_hmac_hash (key, &h, source, len);
- GNUNET_CRYPTO_kdf (out, sizeof (*out), ctx, sizeof (ctx),
- &h, sizeof (h), NULL);
-}
-
-
-/**
- * Encrypt data with the axolotl 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.
- *
- * @return Size of the encrypted data.
- */
-static int
-t_ax_encrypt (struct CadetTunnel *t, void *dst, const void *src, size_t size)
-{
- struct GNUNET_CRYPTO_SymmetricSessionKey MK;
- struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
- struct CadetTunnelAxolotl *ax;
- size_t out_size;
-
- CADET_TIMING_START;
-
- ax = t->ax;
- ax->ratchet_counter++;
- if (GNUNET_YES == ax->ratchet_allowed
- && (ratchet_messages <= ax->ratchet_counter
- || 0 == GNUNET_TIME_absolute_get_remaining (ax->ratchet_expiration).rel_value_us))
- {
- ax->ratchet_flag = GNUNET_YES;
- }
-
- if (GNUNET_YES == ax->ratchet_flag)
- {
- /* Advance ratchet */
- struct GNUNET_CRYPTO_SymmetricSessionKey keys[3];
- struct GNUNET_HashCode dh;
- struct GNUNET_HashCode hmac;
- static const char ctx[] = "axolotl ratchet";
-
- new_ephemeral (t);
- ax->HKs = ax->NHKs;
-
- /* RK, NHKs, CKs = KDF( HMAC-HASH(RK, DH(DHRs, DHRr)) ) */
- GNUNET_CRYPTO_ecc_ecdh (ax->DHRs, &ax->DHRr, &dh);
- t_ax_hmac_hash (&ax->RK, &hmac, &dh, sizeof (dh));
- GNUNET_CRYPTO_kdf (keys, sizeof (keys), ctx, sizeof (ctx),
- &hmac, sizeof (hmac), NULL);
- ax->RK = keys[0];
- ax->NHKs = keys[1];
- ax->CKs = keys[2];
-
- ax->PNs = ax->Ns;
- ax->Ns = 0;
- ax->ratchet_flag = GNUNET_NO;
- ax->ratchet_allowed = GNUNET_NO;
- ax->ratchet_counter = 0;
- ax->ratchet_expiration =
- GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), ratchet_time);
- }
-
- t_hmac_derive_key (&ax->CKs, &MK, "0", 1);
- GNUNET_CRYPTO_symmetric_derive_iv (&iv, &MK, NULL, 0, NULL);
-
- #if DUMP_KEYS_TO_STDERR
- LOG (GNUNET_ERROR_TYPE_DEBUG, " CKs: %s\n",
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKs));
- LOG (GNUNET_ERROR_TYPE_INFO, " AX_ENC with key %u: %s\n", ax->Ns,
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &MK));
- #endif
-
- out_size = GNUNET_CRYPTO_symmetric_encrypt (src, size, &MK, &iv, dst);
- t_hmac_derive_key (&ax->CKs, &ax->CKs, "1", 1);
-
- CADET_TIMING_END;
-
- return out_size;
-}
-
-
-/**
- * Decrypt data with the axolotl tunnel key.
- *
- * @param t Tunnel whose key to use.
- * @param dst Destination for the decrypted data.
- * @param src Source of the ciphertext. Can overlap with @c dst.
- * @param size Size of the ciphertext.
- *
- * @return Size of the decrypted data.
- */
-static int
-t_ax_decrypt (struct CadetTunnel *t, void *dst, const void *src, size_t size)
-{
- struct GNUNET_CRYPTO_SymmetricSessionKey MK;
- struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
- struct CadetTunnelAxolotl *ax;
- size_t out_size;
-
- CADET_TIMING_START;
-
- ax = t->ax;
-
- t_hmac_derive_key (&ax->CKr, &MK, "0", 1);
- GNUNET_CRYPTO_symmetric_derive_iv (&iv, &MK, NULL, 0, NULL);
-
- #if DUMP_KEYS_TO_STDERR
- LOG (GNUNET_ERROR_TYPE_DEBUG, " CKr: %s\n",
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKr));
- LOG (GNUNET_ERROR_TYPE_INFO, " AX_DEC with key %u: %s\n", ax->Nr,
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &MK));
- #endif
-
- GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
- out_size = GNUNET_CRYPTO_symmetric_decrypt (src, size, &MK, &iv, dst);
- GNUNET_assert (out_size == size);
-
- t_hmac_derive_key (&ax->CKr, &ax->CKr, "1", 1);
-
- CADET_TIMING_END;
-
- return out_size;
-}
-
-
-/**
- * Encrypt header with the axolotl header key.
- *
- * @param t Tunnel whose key to use.
- * @param msg Message whose header to encrypt.
- */
-static void
-t_h_encrypt (struct CadetTunnel *t, struct GNUNET_CADET_TunnelEncryptedMessage *msg)
-{
- struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
- struct CadetTunnelAxolotl *ax;
- size_t out_size;
-
- CADET_TIMING_START;
- ax = t->ax;
- GNUNET_CRYPTO_symmetric_derive_iv (&iv, &ax->HKs, NULL, 0, NULL);
-
- #if DUMP_KEYS_TO_STDERR
- LOG (GNUNET_ERROR_TYPE_INFO, " AX_ENC_H with key %s\n",
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKs));
- #endif
-
- out_size = GNUNET_CRYPTO_symmetric_encrypt (&msg->Ns, AX_HEADER_SIZE,
- &ax->HKs, &iv, &msg->Ns);
-
- GNUNET_assert (AX_HEADER_SIZE == out_size);
- CADET_TIMING_END;
-}
-
-
-/**
- * Decrypt header with the current axolotl header key.
- *
- * @param t Tunnel whose current ax HK to use.
- * @param src Message whose header to decrypt.
- * @param dst Where to decrypt header to.
- */
-static void
-t_h_decrypt (struct CadetTunnel *t, const struct GNUNET_CADET_TunnelEncryptedMessage *src,
- struct GNUNET_CADET_TunnelEncryptedMessage *dst)
-{
- struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
- struct CadetTunnelAxolotl *ax;
- size_t out_size;
-
- CADET_TIMING_START;
-
- ax = t->ax;
- GNUNET_CRYPTO_symmetric_derive_iv (&iv, &ax->HKr, NULL, 0, NULL);
-
- #if DUMP_KEYS_TO_STDERR
- LOG (GNUNET_ERROR_TYPE_INFO, " AX_DEC_H with key %s\n",
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKr));
- #endif
-
- out_size = GNUNET_CRYPTO_symmetric_decrypt (&src->Ns, AX_HEADER_SIZE,
- &ax->HKr, &iv, &dst->Ns);
-
- GNUNET_assert (AX_HEADER_SIZE == out_size);
-
- CADET_TIMING_END;
-}
-
-
-/**
- * Decrypt and verify data with the appropriate tunnel key and verify that the
- * data has not been altered since it was sent by the remote peer.
- *
- * @param t Tunnel whose key to use.
- * @param dst Destination for the plaintext.
- * @param src Source of the message. Can overlap with @c dst.
- * @param size Size of the message.
- *
- * @return Size of the decrypted data, -1 if an error was encountered.
- */
-static int
-try_old_ax_keys (struct CadetTunnel *t, void *dst,
- const struct GNUNET_CADET_TunnelEncryptedMessage *src, size_t size)
-{
- struct CadetTunnelSkippedKey *key;
- struct GNUNET_ShortHashCode *hmac;
- struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
- struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header;
- struct GNUNET_CRYPTO_SymmetricSessionKey *valid_HK;
- size_t esize;
- size_t res;
- size_t len;
- unsigned int N;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying old keys\n");
- hmac = &plaintext_header.hmac;
- esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
-
- /* Find a correct Header Key */
- for (key = t->ax->skipped_head; NULL != key; key = key->next)
- {
- #if DUMP_KEYS_TO_STDERR
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Trying hmac with key %s\n",
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->HK));
- #endif
- t_hmac (&src->Ns, AX_HEADER_SIZE + esize, 0, &key->HK, hmac);
- if (0 == memcmp (hmac, &src->hmac, sizeof (*hmac)))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " hmac correct\n");
- valid_HK = &key->HK;
- break;
- }
- }
- if (NULL == key)
- return -1;
-
- /* Should've been checked in -cadet_connection.c handle_cadet_encrypted. */
- GNUNET_assert (size > sizeof (struct GNUNET_CADET_TunnelEncryptedMessage));
- len = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
- GNUNET_assert (len >= sizeof (struct GNUNET_MessageHeader));
-
- /* Decrypt header */
- GNUNET_CRYPTO_symmetric_derive_iv (&iv, &key->HK, NULL, 0, NULL);
- res = GNUNET_CRYPTO_symmetric_decrypt (&src->Ns, AX_HEADER_SIZE,
- &key->HK, &iv, &plaintext_header.Ns);
- GNUNET_assert (AX_HEADER_SIZE == res);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Message %u, previous: %u\n",
- ntohl (plaintext_header.Ns), ntohl (plaintext_header.PNs));
-
- /* Find the correct Message Key */
- N = ntohl (plaintext_header.Ns);
- while (NULL != key && N != key->Kn)
- key = key->next;
- if (NULL == key || 0 != memcmp (&key->HK, valid_HK, sizeof (*valid_HK)))
- return -1;
-
- #if DUMP_KEYS_TO_STDERR
- LOG (GNUNET_ERROR_TYPE_INFO, " AX_DEC_H with skipped key %s\n",
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->HK));
- LOG (GNUNET_ERROR_TYPE_INFO, " AX_DEC with skipped key %u: %s\n",
- key->Kn, GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->MK));
- #endif
-
- /* Decrypt payload */
- GNUNET_CRYPTO_symmetric_derive_iv (&iv, &key->MK, NULL, 0, NULL);
- res = GNUNET_CRYPTO_symmetric_decrypt (&src[1], len, &key->MK, &iv, dst);
-
- /* Remove key */
- GNUNET_CONTAINER_DLL_remove (t->ax->skipped_head, t->ax->skipped_tail, key);
- t->ax->skipped--;
- GNUNET_free (key); /* GNUNET_free overwrites memory with 0xbaadf00d */
-
- return res;
-}
-
-
-/**
- * Delete a key from the list of skipped keys.
- *
- * @param t Tunnel to delete from.
- * @param HKr Header Key to use.
- */
-static void
-store_skipped_key (struct CadetTunnel *t,
- const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr)
-{
- struct CadetTunnelSkippedKey *key;
-
- key = GNUNET_new (struct CadetTunnelSkippedKey);
- key->timestamp = GNUNET_TIME_absolute_get ();
- key->Kn = t->ax->Nr;
- key->HK = t->ax->HKr;
- t_hmac_derive_key (&t->ax->CKr, &key->MK, "0", 1);
- #if DUMP_KEYS_TO_STDERR
- LOG (GNUNET_ERROR_TYPE_DEBUG, " storing MK for Nr %u: %s\n",
- key->Kn, GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->MK));
- LOG (GNUNET_ERROR_TYPE_DEBUG, " for CKr: %s\n",
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &t->ax->CKr));
- #endif
- t_hmac_derive_key (&t->ax->CKr, &t->ax->CKr, "1", 1);
- GNUNET_CONTAINER_DLL_insert (t->ax->skipped_head, t->ax->skipped_tail, key);
- t->ax->Nr++;
- t->ax->skipped++;
-}
-
-
-/**
- * Delete a key from the list of skipped keys.
- *
- * @param t Tunnel to delete from.
- * @param key Key to delete.
- */
-static void
-delete_skipped_key (struct CadetTunnel *t, struct CadetTunnelSkippedKey *key)
-{
- GNUNET_CONTAINER_DLL_remove (t->ax->skipped_head, t->ax->skipped_tail, key);
- GNUNET_free (key);
- t->ax->skipped--;
-}
-
-
-/**
- * Stage skipped AX keys and calculate the message key.
- *
- * Stores each HK and MK for skipped messages.
- *
- * @param t Tunnel where to stage the keys.
- * @param HKr Header key.
- * @param Np Received meesage number.
- *
- * @return GNUNET_OK if keys were stored.
- * GNUNET_SYSERR if an error ocurred (Np not expected).
- */
-static int
-store_ax_keys (struct CadetTunnel *t,
- const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr,
- uint32_t Np)
-{
- int gap;
-
-
- gap = Np - t->ax->Nr;
- LOG (GNUNET_ERROR_TYPE_INFO, "Storing keys [%u, %u)\n", t->ax->Nr, Np);
- if (MAX_KEY_GAP < gap)
- {
- /* Avoid DoS (forcing peer to do 2*33 chain HMAC operations) */
- /* TODO: start new key exchange on return */
- GNUNET_break_op (0);
- LOG (GNUNET_ERROR_TYPE_WARNING, "Got message %u, expected %u+\n",
- Np, t->ax->Nr);
- return GNUNET_SYSERR;
- }
- if (0 > gap)
- {
- /* Delayed message: don't store keys, flag to try old keys. */
- return GNUNET_SYSERR;
- }
-
- while (t->ax->Nr < Np)
- store_skipped_key (t, HKr);
-
- while (t->ax->skipped > MAX_SKIPPED_KEYS)
- delete_skipped_key (t, t->ax->skipped_tail);
-
- return GNUNET_OK;
-}
-
-
-/**
- * Decrypt and verify data with the appropriate tunnel key and verify that the
- * data has not been altered since it was sent by the remote peer.
- *
- * @param t Tunnel whose key to use.
- * @param dst Destination for the plaintext.
- * @param src Source of the message. Can overlap with @c dst.
- * @param size Size of the message.
- *
- * @return Size of the decrypted data, -1 if an error was encountered.
- */
-static int
-t_ax_decrypt_and_validate (struct CadetTunnel *t, void *dst,
- const struct GNUNET_CADET_TunnelEncryptedMessage *src,
- size_t size)
-{
- struct CadetTunnelAxolotl *ax;
- struct GNUNET_ShortHashCode msg_hmac;
- struct GNUNET_HashCode hmac;
- struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header;
- uint32_t Np;
- uint32_t PNp;
- size_t esize; /* Size of encryped payload */
- size_t osize; /* Size of output (decrypted payload) */
-
- esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
- ax = t->ax;
- if (NULL == ax)
- return -1;
-
- /* Try current HK */
- t_hmac (&src->Ns, AX_HEADER_SIZE + esize, 0, &ax->HKr, &msg_hmac);
- if (0 != memcmp (&msg_hmac, &src->hmac, sizeof (msg_hmac)))
- {
- static const char ctx[] = "axolotl ratchet";
- struct GNUNET_CRYPTO_SymmetricSessionKey keys[3]; /* RKp, NHKp, CKp */
- struct GNUNET_CRYPTO_SymmetricSessionKey HK;
- struct GNUNET_HashCode dh;
- struct GNUNET_CRYPTO_EcdhePublicKey *DHRp;
-
- /* Try Next HK */
- LOG (GNUNET_ERROR_TYPE_DEBUG, " trying next HK\n");
- t_hmac (&src->Ns, AX_HEADER_SIZE + esize, 0, &ax->NHKr, &msg_hmac);
- if (0 != memcmp (&msg_hmac, &src->hmac, sizeof (msg_hmac)))
- {
- /* Try the skipped keys, if that fails, we're out of luck. */
- return try_old_ax_keys (t, dst, src, size);
- }
- LOG (GNUNET_ERROR_TYPE_INFO, "next HK worked\n");
-
- HK = ax->HKr;
- ax->HKr = ax->NHKr;
- t_h_decrypt (t, src, &plaintext_header);
- Np = ntohl (plaintext_header.Ns);
- PNp = ntohl (plaintext_header.PNs);
- DHRp = &plaintext_header.DHRs;
- store_ax_keys (t, &HK, PNp);
-
- /* RKp, NHKp, CKp = KDF (HMAC-HASH (RK, DH (DHRp, DHRs))) */
- GNUNET_CRYPTO_ecc_ecdh (ax->DHRs, DHRp, &dh);
- t_ax_hmac_hash (&ax->RK, &hmac, &dh, sizeof (dh));
- GNUNET_CRYPTO_kdf (keys, sizeof (keys), ctx, sizeof (ctx),
- &hmac, sizeof (hmac), NULL);
-
- /* Commit "purported" keys */
- ax->RK = keys[0];
- ax->NHKr = keys[1];
- ax->CKr = keys[2];
- ax->DHRr = *DHRp;
- ax->Nr = 0;
- ax->ratchet_allowed = GNUNET_YES;
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "current HK\n");
- t_h_decrypt (t, src, &plaintext_header);
- Np = ntohl (plaintext_header.Ns);
- PNp = ntohl (plaintext_header.PNs);
- }
- LOG (GNUNET_ERROR_TYPE_INFO, " got AX Nr %u\n", Np);
- if (Np != ax->Nr)
- if (GNUNET_OK != store_ax_keys (t, &ax->HKr, Np))
- /* Try the skipped keys, if that fails, we're out of luck. */
- return try_old_ax_keys (t, dst, src, size);
-
- osize = t_ax_decrypt (t, dst, &src[1], esize);
- ax->Nr = Np + 1;
-
- if (osize != esize)
- {
- GNUNET_break_op (0);
- return -1;
- }
-
- return osize;
-}
-
-
-/**
- * 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 CadetTunnel *t)
-{
- struct CadetTConnection *iter;
- struct CadetConnection *best;
- unsigned int qn;
- unsigned int lowest_q;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel_get_connection %s\n", GCT_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",
- GCC_2s (iter->c), GCC_get_state (iter->c));
- if (CADET_CONNECTION_READY == GCC_get_state (iter->c))
- {
- qn = GCC_get_qn (iter->c, GCC_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", GCC_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 CadetTunnelQueue *qt = cls;
- struct CadetTunnel *t;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "tun_message_sent\n");
-
- GNUNET_assert (NULL != qt->cont);
- t = NULL == c ? NULL : GCC_get_tunnel (c);
- qt->cont (qt->cont_cls, t, qt, type, size);
- GNUNET_free (qt);
-}
-
-
-static unsigned int
-count_queued_data (const struct CadetTunnel *t)
-{
- struct CadetTunnelDelayed *iter;
- unsigned int count;
-
- for (count = 0, iter = t->tq_head; iter != NULL; iter = iter->next)
- count++;
-
- return count;
-}
-
-/**
- * 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 CadetTunnel *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", GCT_2s (t));
-
- GNUNET_assert (GNUNET_NO == is_ready (t));
-
- tqd = GNUNET_malloc (sizeof (struct CadetTunnelDelayed) + size);
-
- tqd->t = t;
- GNUNET_memcpy (&tqd[1], msg, size);
- GNUNET_CONTAINER_DLL_insert_tail (t->tq_head, t->tq_tail, tqd);
- return tqd;
-}
-
-
-/**
- * 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 or an error happens and message is dropped.
- */
-static struct CadetTunnelQueue *
-send_prebuilt_message (const struct GNUNET_MessageHeader *message,
- struct CadetTunnel *t,
- struct CadetConnection *c,
- int force,
- GCT_sent cont,
- void *cont_cls,
- struct CadetTunnelQueue *existing_q)
-{
- struct GNUNET_MessageHeader *msg;
- struct GNUNET_CADET_TunnelEncryptedMessage *ax_msg;
- struct CadetTunnelQueue *tq;
- size_t size = ntohs (message->size);
- char cbuf[sizeof (struct GNUNET_CADET_TunnelEncryptedMessage) + size] GNUNET_ALIGN;
- size_t esize;
- uint16_t type;
- int fwd;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT Send on Tunnel %s\n", GCT_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 CadetTunnelQueue);
- tq->tqd = tqd;
- tqd->tq = tq;
- tq->cont = cont;
- tq->cont_cls = cont_cls;
- return tq;
- }
-
- GNUNET_assert (GNUNET_NO == GCT_is_loopback (t));
-
- ax_msg = (struct GNUNET_CADET_TunnelEncryptedMessage *) cbuf;
- msg = &ax_msg->header;
- msg->size = htons (sizeof (struct GNUNET_CADET_TunnelEncryptedMessage) + size);
- msg->type = htons (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED);
- esize = t_ax_encrypt (t, &ax_msg[1], message, size);
- ax_msg->Ns = htonl (t->ax->Ns++);
- ax_msg->PNs = htonl (t->ax->PNs);
- GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->DHRs, &ax_msg->DHRs);
- t_h_encrypt (t, ax_msg);
- t_hmac (&ax_msg->Ns, AX_HEADER_SIZE + esize, 0, &t->ax->HKs, &ax_msg->hmac);
- GNUNET_assert (esize == size);
-
- if (NULL == c)
- c = tunnel_get_connection (t);
- if (NULL == c)
- {
- /* Why is tunnel 'ready'? Should have been queued! */
- if (NULL != t->destroy_task)
- {
- GNUNET_break (0);
- GCT_debug (t, GNUNET_ERROR_TYPE_WARNING);
- }
- return NULL; /* Drop... */
- }
- fwd = GCC_is_origin (c, GNUNET_YES);
- ax_msg->cid = *GCC_get_id (c);
- ax_msg->cemi = GCC_get_pid (c, fwd);
-
- type = htons (message->type);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sending message of type %s with CEMI %u and CID %s\n",
- GC_m2s (type),
- htonl (ax_msg->cemi.pid),
- GNUNET_sh2s (&ax_msg->cid.connection_of_tunnel));
-
- if (NULL == cont)
- {
- (void) GCC_send_prebuilt_message (msg,
- type,
- ax_msg->cemi,
- c,
- fwd,
- force, NULL, NULL);
- return NULL;
- }
- if (NULL == existing_q)
- {
- tq = GNUNET_new (struct CadetTunnelQueue); /* FIXME valgrind: leak*/
- }
- else
- {
- tq = existing_q;
- tq->tqd = NULL;
- }
- tq->cont = cont;
- tq->cont_cls = cont_cls;
- tq->cq = GCC_send_prebuilt_message (msg,
- type,
- ax_msg->cemi,
- c,
- fwd,
- force,
- &tun_message_sent, tq);
- GNUNET_assert (NULL != tq->cq);
-
- 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 CadetTunnel *t)
-{
- struct CadetTunnelDelayed *tqd;
- struct CadetTunnelDelayed *next;
- unsigned int room;
-
- LOG (GNUNET_ERROR_TYPE_INFO, "Send queued data, tunnel %s\n", GCT_2s (t));
-
- if (GCT_is_loopback (t))
- {
- GNUNET_break (0);
- return;
- }
-
- if (GNUNET_NO == is_ready (t))
- {
- LOG (GNUNET_ERROR_TYPE_WARNING, " not ready yet: %s/%s\n",
- estate2s (t->estate), cstate2s (t->cstate));
- return;
- }
-
- room = GCT_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, "GCT_send_queued_data end\n", GCP_2s (t->peer));
-}
-
-
-/**
- * @brief Resend the KX until we complete the handshake.
- *
- * @param cls Closure (tunnel).
- */
-static void
-kx_resend (void *cls)
-{
- struct CadetTunnel *t = cls;
-
- t->rekey_task = NULL;
- if (CADET_TUNNEL_KEY_OK == t->estate)
- {
- /* Should have been canceled on estate change */
- GNUNET_break (0);
- return;
- }
-
- GCT_send_kx (t, CADET_TUNNEL_KEY_AX_SENT >= t->estate);
-}
-
-
-/**
- * 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.
- */
-static void
-ephm_sent (void *cls,
- struct CadetConnection *c,
- struct CadetConnectionQueue *q,
- uint16_t type, int fwd, size_t size)
-{
- struct CadetTunnel *t = cls;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "ephemeral sent %s\n", GC_m2s (type));
-
- t->ephm_h = NULL;
-
- if (CADET_TUNNEL_KEY_OK == t->estate)
- return;
-
- if (NULL != t->rekey_task)
- {
- GNUNET_break (0);
- GCT_debug (t, GNUNET_ERROR_TYPE_WARNING);
- GNUNET_SCHEDULER_cancel (t->rekey_task);
- }
- t->rekey_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
- &kx_resend, t);
-
-}
-
-
-/**
- * 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 CadetTunnel *t = value;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "GCT_shutdown destroying tunnel at %p\n", t);
- GCT_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 CadetTunnel *t,
- struct GNUNET_CADET_ChannelTunnelNumber gid)
-{
- struct GNUNET_CADET_ChannelManageMessage msg;
-
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
- msg.header.size = htons (sizeof (msg));
- msg.ctn = gid;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "WARNING destroying unknown channel %u on tunnel %s\n",
- ntohl (gid.cn),
- GCT_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 CadetTunnel *t,
- const struct GNUNET_CADET_ChannelAppDataMessage *msg,
- int fwd)
-{
- struct CadetChannel *ch;
- char buf[128];
- size_t size;
- uint16_t type;
-
- /* Check size */
- size = ntohs (msg->header.size);
- if (size <
- sizeof (struct GNUNET_CADET_ChannelAppDataMessage) +
- sizeof (struct GNUNET_MessageHeader))
- {
- GNUNET_break (0);
- return;
- }
- type = ntohs (msg[1].header.type);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " payload of type %s\n", GC_m2s (type));
- SPRINTF (buf, "# received payload of type %hu", type);
- GNUNET_STATISTICS_update (stats, buf, 1, GNUNET_NO);
-
-
- /* Check channel */
- ch = GCT_get_channel (t, msg->ctn);
- if (NULL == ch)
- {
- GNUNET_STATISTICS_update (stats,
- "# data on unknown channel",
- 1,
- GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "channel 0x%X unknown\n",
- ntohl (msg->ctn.cn));
- send_channel_destroy (t, msg->ctn);
- return;
- }
-
- GCCH_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 CadetTunnel *t,
- const struct GNUNET_CADET_ChannelDataAckMessage *msg,
- int fwd)
-{
- struct CadetChannel *ch;
- size_t size;
-
- /* Check size */
- size = ntohs (msg->header.size);
- if (size != sizeof (struct GNUNET_CADET_ChannelDataAckMessage))
- {
- GNUNET_break (0);
- return;
- }
-
- /* Check channel */
- ch = GCT_get_channel (t, msg->ctn);
- 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->ctn.cn));
- return;
- }
-
- GCCH_handle_data_ack (ch, msg, fwd);
-}
-
-
-/**
- * Handle channel create.
- *
- * @param t Tunnel on which the message came.
- * @param msg ChannelCreate message.
- */
-static void
-handle_ch_create (struct CadetTunnel *t,
- const struct GNUNET_CADET_ChannelOpenMessage *msg)
-{
- struct CadetChannel *ch;
- size_t size;
-
- /* Check size */
- size = ntohs (msg->header.size);
- if (size != sizeof (struct GNUNET_CADET_ChannelOpenMessage))
- {
- GNUNET_break_op (0);
- return;
- }
-
- /* Check channel */
- ch = GCT_get_channel (t, msg->ctn);
- if (NULL != ch && ! GCT_is_loopback (t))
- {
- /* Probably a retransmission, safe to ignore */
- LOG (GNUNET_ERROR_TYPE_DEBUG, " already exists...\n");
- }
- ch = GCCH_handle_create (t, msg);
- if (NULL != ch)
- GCT_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 CadetTunnel *t,
- const struct GNUNET_CADET_ChannelManageMessage *msg)
-{
- struct CadetChannel *ch;
- size_t size;
-
- /* Check size */
- size = ntohs (msg->header.size);
- if (size != sizeof (struct GNUNET_CADET_ChannelManageMessage))
- {
- GNUNET_break (0);
- return;
- }
-
- /* Check channel */
- ch = GCT_get_channel (t, msg->ctn);
- 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->ctn.cn));
- return;
- }
-
- GCCH_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 CadetTunnel *t,
- const struct GNUNET_CADET_ChannelManageMessage *msg,
- int fwd)
-{
- struct CadetChannel *ch;
- size_t size;
-
- /* Check size */
- size = ntohs (msg->header.size);
- if (size != sizeof (struct GNUNET_CADET_ChannelManageMessage))
- {
- GNUNET_break (0);
- return;
- }
-
- /* Check channel */
- ch = GCT_get_channel (t, msg->ctn);
- 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->ctn.cn));
- return;
- }
-
- GCCH_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 CadetTunnel *t,
- const struct GNUNET_CADET_ChannelManageMessage *msg,
- int fwd)
-{
- struct CadetChannel *ch;
- size_t size;
-
- /* Check size */
- size = ntohs (msg->header.size);
- if (size != sizeof (struct GNUNET_CADET_ChannelManageMessage))
- {
- GNUNET_break (0);
- return;
- }
-
- /* Check channel */
- ch = GCT_get_channel (t, msg->ctn);
- if (NULL == ch)
- {
- /* Probably a retransmission, safe to ignore */
- return;
- }
-
- GCCH_handle_destroy (ch, msg, fwd);
-}
-
-
-/**
- * Free Axolotl data.
- *
- * @param t Tunnel.
- */
-static void
-destroy_ax (struct CadetTunnel *t)
-{
- if (NULL == t->ax)
- return;
-
- GNUNET_free_non_null (t->ax->DHRs);
- GNUNET_free_non_null (t->ax->kx_0);
- while (NULL != t->ax->skipped_head)
- delete_skipped_key (t, t->ax->skipped_head);
- GNUNET_assert (0 == t->ax->skipped);
-
- GNUNET_free (t->ax);
- t->ax = NULL;
-
- if (NULL != t->rekey_task)
- {
- GNUNET_SCHEDULER_cancel (t->rekey_task);
- t->rekey_task = NULL;
- }
- if (NULL != t->ephm_h)
- {
- GCC_cancel (t->ephm_h);
- t->ephm_h = NULL;
- }
-}
-
-
-/**
- * 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 CadetTunnel *t,
- const struct GNUNET_MessageHeader *msgh,
- int fwd)
-{
- uint16_t type;
- char buf[256];
-
- type = ntohs (msgh->type);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "<-- %s on %s\n", GC_m2s (type), GCT_2s (t));
- SPRINTF (buf, "# received encrypted of type %hu (%s)", type, GC_m2s (type));
- GNUNET_STATISTICS_update (stats, buf, 1, GNUNET_NO);
-
- switch (type)
- {
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE:
- /* Do nothing, connection aleady got updated. */
- GNUNET_STATISTICS_update (stats, "# keepalives received", 1, GNUNET_NO);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA:
- /* Don't send hop ACK, wait for client to ACK */
- handle_data (t, (struct GNUNET_CADET_ChannelAppDataMessage *) msgh, fwd);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK:
- handle_data_ack (t, (struct GNUNET_CADET_ChannelDataAckMessage *) msgh, fwd);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN:
- handle_ch_create (t, (struct GNUNET_CADET_ChannelOpenMessage *) msgh);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED:
- handle_ch_nack (t, (struct GNUNET_CADET_ChannelManageMessage *) msgh);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK:
- handle_ch_ack (t, (struct GNUNET_CADET_ChannelManageMessage *) msgh, fwd);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
- handle_ch_destroy (t, (struct GNUNET_CADET_ChannelManageMessage *) msgh, fwd);
- break;
-
- default:
- GNUNET_break_op (0);
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "end-to-end message not known (%u)\n",
- ntohs (msgh->type));
- GCT_debug (t, GNUNET_ERROR_TYPE_WARNING);
- }
-}
-
-
-/******************************************************************************/
-/******************************** API ***********************************/
-/******************************************************************************/
-
-/**
- * Decrypt and process an encrypted message.
- *
- * Calls the appropriate handler for a message in a channel of a local tunnel.
- *
- * @param t Tunnel this message came on.
- * @param msg Message header.
- */
-void
-GCT_handle_encrypted (struct CadetTunnel *t,
- const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
-{
- uint16_t size = ntohs (msg->header.size);
- char cbuf [size];
- int decrypted_size;
- const struct GNUNET_MessageHeader *msgh;
- unsigned int off;
-
- GNUNET_STATISTICS_update (stats, "# received encrypted", 1, GNUNET_NO);
-
- decrypted_size = t_ax_decrypt_and_validate (t, cbuf, msg, size);
-
- if (-1 == decrypted_size)
- {
- GNUNET_STATISTICS_update (stats, "# unable to decrypt", 1, GNUNET_NO);
- if (CADET_TUNNEL_KEY_AX_AUTH_SENT <= t->estate)
- {
- GNUNET_break_op (0);
- LOG (GNUNET_ERROR_TYPE_WARNING, "Wrong crypto, tunnel %s\n", GCT_2s (t));
- GCT_debug (t, GNUNET_ERROR_TYPE_WARNING);
- }
- return;
- }
- GCT_change_estate (t, CADET_TUNNEL_KEY_OK);
-
- /* FIXME: this is bad, as the structs returned from
- this loop may be unaligned, see util's MST for
- how to do this right. */
- off = 0;
- while (off + sizeof (struct GNUNET_MessageHeader) <= decrypted_size)
- {
- uint16_t msize;
-
- msgh = (const struct GNUNET_MessageHeader *) &cbuf[off];
- msize = ntohs (msgh->size);
- if (msize < sizeof (struct GNUNET_MessageHeader))
- {
- GNUNET_break_op (0);
- return;
- }
- if (off + msize < decrypted_size)
- {
- GNUNET_break_op (0);
- return;
- }
- handle_decrypted (t, msgh, GNUNET_SYSERR);
- off += msize;
- }
-}
-
-
-/**
- * Handle a Key eXchange message.
- *
- * @param t Tunnel on which the message came.
- * @param msg KX message itself.
- */
-void
-GCT_handle_kx (struct CadetTunnel *t,
- const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
-{
- struct CadetTunnelAxolotl *ax;
- struct GNUNET_HashCode key_material[3];
- struct GNUNET_CRYPTO_SymmetricSessionKey keys[5];
- const char salt[] = "CADET Axolotl salt";
- const struct GNUNET_PeerIdentity *pid;
- int am_I_alice;
-
- CADET_TIMING_START;
-
- LOG (GNUNET_ERROR_TYPE_INFO, "<== { KX} on %s\n", GCT_2s (t));
-
- if (NULL == t->ax)
- {
- /* Something is wrong if ax is NULL. Whose fault it is? */
- return;
- }
- ax = t->ax;
-
- pid = GCT_get_destination (t);
- if (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, pid))
- am_I_alice = GNUNET_YES;
- else if (0 < GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, pid))
- am_I_alice = GNUNET_NO;
- else
- {
- GNUNET_break_op (0);
- return;
- }
-
- if (0 != (GNUNET_CADET_KX_FLAG_FORCE_REPLY & ntohl (msg->flags)))
- {
- if (NULL != t->rekey_task)
- {
- GNUNET_SCHEDULER_cancel (t->rekey_task);
- t->rekey_task = NULL;
- }
- GCT_send_kx (t, GNUNET_NO);
- }
-
- if (0 == memcmp (&ax->DHRr, &msg->ratchet_key, sizeof(msg->ratchet_key)))
- {
- LOG (GNUNET_ERROR_TYPE_INFO, " known ratchet key, exit\n");
- return;
- }
-
- LOG (GNUNET_ERROR_TYPE_INFO, " is Alice? %s\n", am_I_alice ? "YES" : "NO");
-
- ax->DHRr = msg->ratchet_key;
-
- /* ECDH A B0 */
- if (GNUNET_YES == am_I_alice)
- {
- GNUNET_CRYPTO_eddsa_ecdh (id_key, /* A */
- &msg->ephemeral_key, /* B0 */
- &key_material[0]);
- }
- else
- {
- GNUNET_CRYPTO_ecdh_eddsa (ax->kx_0, /* B0 */
- &pid->public_key, /* A */
- &key_material[0]);
- }
-
- /* ECDH A0 B */
- if (GNUNET_YES == am_I_alice)
- {
- GNUNET_CRYPTO_ecdh_eddsa (ax->kx_0, /* A0 */
- &pid->public_key, /* B */
- &key_material[1]);
- }
- else
- {
- GNUNET_CRYPTO_eddsa_ecdh (id_key, /* A */
- &msg->ephemeral_key, /* B0 */
- &key_material[1]);
-
-
- }
-
- /* ECDH A0 B0 */
- /* (This is the triple-DH, we could probably safely skip this,
- as A0/B0 are already in the key material.) */
- GNUNET_CRYPTO_ecc_ecdh (ax->kx_0, /* A0 or B0 */
- &msg->ephemeral_key, /* B0 or A0 */
- &key_material[2]);
-
- #if DUMP_KEYS_TO_STDERR
- {
- unsigned int i;
- for (i = 0; i < 3; i++)
- LOG (GNUNET_ERROR_TYPE_INFO, "km[%u]: %s\n",
- i, GNUNET_h2s (&key_material[i]));
- }
- #endif
-
- /* KDF */
- GNUNET_CRYPTO_kdf (keys, sizeof (keys),
- salt, sizeof (salt),
- &key_material, sizeof (key_material), NULL);
-
- if (0 == memcmp (&ax->RK, &keys[0], sizeof(ax->RK)))
- {
- LOG (GNUNET_ERROR_TYPE_INFO, " known handshake key, exit\n");
- return;
- }
- ax->RK = keys[0];
- if (GNUNET_YES == am_I_alice)
- {
- ax->HKr = keys[1];
- ax->NHKs = keys[2];
- ax->NHKr = keys[3];
- ax->CKr = keys[4];
- ax->ratchet_flag = GNUNET_YES;
- }
- else
- {
- ax->HKs = keys[1];
- ax->NHKr = keys[2];
- ax->NHKs = keys[3];
- ax->CKs = keys[4];
- ax->ratchet_flag = GNUNET_NO;
- ax->ratchet_allowed = GNUNET_NO;
- ax->ratchet_counter = 0;
- ax->ratchet_expiration =
- GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), ratchet_time);
- }
- ax->PNs = 0;
- ax->Nr = 0;
- ax->Ns = 0;
-
- GCT_change_estate (t, CADET_TUNNEL_KEY_AX_AUTH_SENT);
- send_queued_data (t);
-
- CADET_TIMING_END;
-}
-
-/**
- * Initialize the tunnel subsystem.
- *
- * @param c Configuration handle.
- * @param key ECC private key, to derive all other keys and do crypto.
- */
-void
-GCT_init (const struct GNUNET_CONFIGURATION_Handle *c,
- const struct GNUNET_CRYPTO_EddsaPrivateKey *key)
-{
- unsigned int expected_overhead;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
-
- expected_overhead = 0;
- expected_overhead += sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
- expected_overhead += sizeof (struct GNUNET_CADET_ChannelAppDataMessage);
- expected_overhead += sizeof (struct GNUNET_CADET_ConnectionEncryptedAckMessage);
- GNUNET_assert (GNUNET_CONSTANTS_CADET_P2P_OVERHEAD == expected_overhead);
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (c,
- "CADET",
- "RATCHET_MESSAGES",
- &ratchet_messages))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
- "CADET",
- "RATCHET_MESSAGES",
- "USING DEFAULT");
- ratchet_messages = 64;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (c,
- "CADET",
- "RATCHET_TIME",
- &ratchet_time))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
- "CADET", "RATCHET_TIME", "USING DEFAULT");
- ratchet_time = GNUNET_TIME_UNIT_HOURS;
- }
-
-
- id_key = key;
- tunnels = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES);
-}
-
-
-/**
- * Shut down the tunnel subsystem.
- */
-void
-GCT_shutdown (void)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down tunnels\n");
- GNUNET_CONTAINER_multipeermap_iterate (tunnels, &destroy_iterator, NULL);
- GNUNET_CONTAINER_multipeermap_destroy (tunnels);
-}
-
-
-/**
- * Create a tunnel.
- *
- * @param destination Peer this tunnel is towards.
- */
-struct CadetTunnel *
-GCT_new (struct CadetPeer *destination)
-{
- struct CadetTunnel *t;
-
- t = GNUNET_new (struct CadetTunnel);
- t->next_ctn.cn = 0;
- t->peer = destination;
-
- if (GNUNET_OK !=
- GNUNET_CONTAINER_multipeermap_put (tunnels, GCP_get_id (destination), t,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
- {
- GNUNET_break (0);
- GNUNET_free (t);
- return NULL;
- }
- t->ax = GNUNET_new (struct CadetTunnelAxolotl);
- new_ephemeral (t);
- t->ax->kx_0 = GNUNET_CRYPTO_ecdhe_key_create ();
- return t;
-}
-
-
-/**
- * Change the tunnel's connection state.
- *
- * @param t Tunnel whose connection state to change.
- * @param cstate New connection state.
- */
-void
-GCT_change_cstate (struct CadetTunnel* t, enum CadetTunnelCState cstate)
-{
- if (NULL == t)
- return;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s cstate %s => %s\n",
- GCP_2s (t->peer), cstate2s (t->cstate), cstate2s (cstate));
- if (myid != GCP_get_short_id (t->peer) &&
- CADET_TUNNEL_READY != t->cstate &&
- CADET_TUNNEL_READY == cstate)
- {
- t->cstate = cstate;
- if (CADET_TUNNEL_KEY_OK == t->estate)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered send queued data\n");
- send_queued_data (t);
- }
- else if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered KX\n");
- GCT_send_kx (t, GNUNET_NO);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "estate %s\n", estate2s (t->estate));
- }
- }
- t->cstate = cstate;
-
- if (CADET_TUNNEL_READY == cstate
- && CONNECTIONS_PER_TUNNEL <= GCT_count_connections (t))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered stop dht\n");
- GCP_stop_search (t->peer);
- }
-}
-
-
-/**
- * Change the tunnel encryption state.
- *
- * If the encryption state changes to OK, stop the rekey task.
- *
- * @param t Tunnel whose encryption state to change, or NULL.
- * @param state New encryption state.
- */
-void
-GCT_change_estate (struct CadetTunnel* t, enum CadetTunnelEState state)
-{
- enum CadetTunnelEState old;
-
- if (NULL == t)
- return;
-
- old = t->estate;
- t->estate = state;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s estate was %s\n",
- GCP_2s (t->peer), estate2s (old));
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s estate is now %s\n",
- GCP_2s (t->peer), estate2s (t->estate));
-
- if (CADET_TUNNEL_KEY_OK != old && CADET_TUNNEL_KEY_OK == t->estate)
- {
- if (NULL != t->rekey_task)
- {
- GNUNET_SCHEDULER_cancel (t->rekey_task);
- t->rekey_task = NULL;
- }
- /* Send queued data if tunnel is not loopback */
- if (myid != GCP_get_short_id (t->peer))
- send_queued_data (t);
- }
-}
-
-
-/**
- * @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).
- */
-static void
-trim_connections (void *cls)
-{
- struct CadetTunnel *t = cls;
-
- t->trim_connections_task = NULL;
- if (GCT_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 ((iter->created.abs_value_us > c->created.abs_value_us)
- && GNUNET_NO == GCC_is_direct (iter->c))
- {
- c = iter;
- }
- }
- if (NULL != c)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Too many connections on tunnel %s\n",
- GCT_2s (t));
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying connection %s\n",
- GCC_2s (c->c));
- GCC_destroy (c->c);
- }
- else
- {
- GNUNET_break (0);
- }
- }
-}
-
-
-/**
- * Add a connection to a tunnel.
- *
- * @param t Tunnel.
- * @param c Connection.
- */
-void
-GCT_add_connection (struct CadetTunnel *t, struct CadetConnection *c)
-{
- struct CadetTConnection *aux;
-
- GNUNET_assert (NULL != c);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "add connection %s\n", GCC_2s (c));
- LOG (GNUNET_ERROR_TYPE_DEBUG, " to tunnel %s\n", GCT_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);
-
- if (CADET_TUNNEL_SEARCHING == t->cstate)
- GCT_change_cstate (t, CADET_TUNNEL_WAITING);
-
- if (NULL != t->trim_connections_task)
- t->trim_connections_task = GNUNET_SCHEDULER_add_now (&trim_connections, t);
-}
-
-
-/**
- * Remove a connection from a tunnel.
- *
- * @param t Tunnel.
- * @param c Connection.
- */
-void
-GCT_remove_connection (struct CadetTunnel *t,
- struct CadetConnection *c)
-{
- struct CadetTConnection *aux;
- struct CadetTConnection *next;
- unsigned int conns;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing connection %s from tunnel %s\n",
- GCC_2s (c), GCT_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);
- }
- }
-
- conns = GCT_count_connections (t);
- if (0 == conns
- && NULL == t->destroy_task
- && CADET_TUNNEL_SHUTDOWN != t->cstate
- && GNUNET_NO == shutting_down)
- {
- if (0 == GCT_count_any_connections (t))
- GCT_change_cstate (t, CADET_TUNNEL_SEARCHING);
- else
- GCT_change_cstate (t, CADET_TUNNEL_WAITING);
- }
-
- /* Start new connections if needed */
- if (CONNECTIONS_PER_TUNNEL > conns
- && CADET_TUNNEL_SHUTDOWN != t->cstate
- && GNUNET_NO == shutting_down)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " too few connections, getting new ones\n");
- GCP_connect (t->peer); /* Will change cstate to WAITING when possible */
- return;
- }
-
- /* If not marked as ready, no change is needed */
- if (CADET_TUNNEL_READY != t->cstate)
- return;
-
- /* Check if any connection is ready to maintain cstate */
- for (aux = t->connection_head; aux != NULL; aux = aux->next)
- if (CADET_CONNECTION_READY == GCC_get_state (aux->c))
- return;
-}
-
-
-/**
- * Add a channel to a tunnel.
- *
- * @param t Tunnel.
- * @param ch Channel.
- */
-void
-GCT_add_channel (struct CadetTunnel *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 (NULL != t->destroy_task)
- {
- GNUNET_SCHEDULER_cancel (t->destroy_task);
- t->destroy_task = NULL;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " undo destroy!\n");
- }
-}
-
-
-/**
- * Remove a channel from a tunnel.
- *
- * @param t Tunnel.
- * @param ch Channel.
- */
-void
-GCT_remove_channel (struct CadetTunnel *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", GCCH_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 ctn Public channel number.
- *
- * @return channel handler, NULL if doesn't exist
- */
-struct CadetChannel *
-GCT_get_channel (struct CadetTunnel *t,
- struct GNUNET_CADET_ChannelTunnelNumber ctn)
-{
- struct CadetTChannel *iter;
-
- if (NULL == t)
- return NULL;
-
- for (iter = t->channel_head; NULL != iter; iter = iter->next)
- {
- if (GCCH_get_id (iter->ch).cn == ctn.cn)
- 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).
- */
-static void
-delayed_destroy (void *cls)
-{
- struct CadetTunnel *t = cls;
- struct CadetTConnection *iter;
-
- t->destroy_task = NULL;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "delayed destroying tunnel %p\n",
- t);
- t->cstate = CADET_TUNNEL_SHUTDOWN;
- for (iter = t->connection_head; NULL != iter; iter = iter->next)
- {
- GCC_send_destroy (iter->c);
- }
- GCT_destroy (t);
-}
-
-
-/**
- * Tunnel is empty: destroy it.
- *
- * Notifies all connections about the destruction.
- *
- * @param t Tunnel to destroy.
- */
-void
-GCT_destroy_empty (struct CadetTunnel *t)
-{
- if (GNUNET_YES == shutting_down)
- return; /* Will be destroyed immediately anyway */
-
- if (NULL != t->destroy_task)
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "Tunnel %s is already scheduled for destruction. Tunnel debug dump:\n",
- GCT_2s (t));
- GCT_debug (t, GNUNET_ERROR_TYPE_WARNING);
- 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: scheduling destruction\n",
- GCT_2s (t));
-
- // FIXME make delay a config option
- t->destroy_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
- &delayed_destroy, t);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduled destroy of %p as %p\n",
- t, t->destroy_task);
-}
-
-
-/**
- * Destroy tunnel if empty (no more channels).
- *
- * @param t Tunnel to destroy if empty.
- */
-void
-GCT_destroy_if_empty (struct CadetTunnel *t)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s destroy if empty\n", GCT_2s (t));
- if (0 < GCT_count_channels (t))
- return;
-
- GCT_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
-GCT_destroy (struct CadetTunnel *t)
-{
- struct CadetTConnection *iter_c;
- struct CadetTConnection *next_c;
- struct CadetTChannel *iter_ch;
- struct CadetTChannel *next_ch;
- unsigned int keepalives_queued;
-
- if (NULL == t)
- return;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "destroying tunnel %s\n",
- GCP_2s (t->peer));
- GNUNET_break (GNUNET_YES ==
- GNUNET_CONTAINER_multipeermap_remove (tunnels,
- GCP_get_id (t->peer), t));
-
- for (iter_c = t->connection_head; NULL != iter_c; iter_c = next_c)
- {
- next_c = iter_c->next;
- GCC_destroy (iter_c->c);
- }
- for (iter_ch = t->channel_head; NULL != iter_ch; iter_ch = next_ch)
- {
- next_ch = iter_ch->next;
- GCCH_destroy (iter_ch->ch);
- /* Should only happen on shutdown, but it's ok. */
- }
- keepalives_queued = 0;
- while (NULL != t->tq_head)
- {
- /* Should have been cleaned by destuction of channel. */
- struct GNUNET_MessageHeader *mh;
- uint16_t type;
-
- mh = (struct GNUNET_MessageHeader *) &t->tq_head[1];
- type = ntohs (mh->type);
- if (0 == keepalives_queued && GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE == type)
- {
- keepalives_queued = 1;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "one keepalive left behind on tunnel shutdown\n");
- }
- else if (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY == type)
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "tunnel destroyed before a CHANNEL_DESTROY was sent to peer\n");
- }
- else
- {
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_ERROR,
- "message left behind on tunnel shutdown: %s\n",
- GC_m2s (type));
- }
- unqueue_data (t->tq_head);
- }
-
-
- if (NULL != t->destroy_task)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "cancelling dest: %p\n",
- t->destroy_task);
- GNUNET_SCHEDULER_cancel (t->destroy_task);
- t->destroy_task = NULL;
- }
-
- if (NULL != t->trim_connections_task)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "cancelling trim: %p\n",
- t->trim_connections_task);
- GNUNET_SCHEDULER_cancel (t->trim_connections_task);
- t->trim_connections_task = NULL;
- }
-
- GNUNET_STATISTICS_update (stats, "# tunnels", -1, GNUNET_NO);
- GCP_set_tunnel (t->peer, NULL);
-
- if (NULL != t->rekey_task)
- {
- GNUNET_SCHEDULER_cancel (t->rekey_task);
- t->rekey_task = NULL;
- }
- if (NULL != t->ax)
- destroy_ax (t);
-
- 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 *
-GCT_use_path (struct CadetTunnel *t, struct CadetPeerPath *path)
-{
- struct CadetConnection *c;
- struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
- unsigned int own_pos;
-
- if (NULL == t || NULL == path)
- {
- GNUNET_break (0);
- return NULL;
- }
-
- if (CADET_TUNNEL_SHUTDOWN == t->cstate)
- {
- GNUNET_break (0);
- return NULL;
- }
-
- for (own_pos = 0; own_pos < path->length; own_pos++)
- {
- if (path->peers[own_pos] == myid)
- break;
- }
- if (own_pos >= path->length)
- {
- GNUNET_break_op (0);
- return NULL;
- }
-
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, &cid, sizeof (cid));
- c = GCC_new (&cid, t, path, own_pos);
- if (NULL == c)
- {
- /* Path was flawed */
- return NULL;
- }
- GCT_add_connection (t, c);
- return c;
-}
-
-
-/**
- * Count all created connections of a tunnel. Not necessarily ready connections!
- *
- * @param t Tunnel on which to count.
- *
- * @return Number of connections created, either being established or ready.
- */
-unsigned int
-GCT_count_any_connections (struct CadetTunnel *t)
-{
- struct CadetTConnection *iter;
- unsigned int count;
-
- if (NULL == t)
- return 0;
-
- for (count = 0, iter = t->connection_head; NULL != iter; iter = iter->next)
- count++;
-
- return count;
-}
-
-
-/**
- * Count established (ready) connections of a tunnel.
- *
- * @param t Tunnel on which to count.
- *
- * @return Number of connections.
- */
-unsigned int
-GCT_count_connections (struct CadetTunnel *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_READY == GCC_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
-GCT_count_channels (struct CadetTunnel *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 CadetTunnelCState
-GCT_get_cstate (struct CadetTunnel *t)
-{
- if (NULL == t)
- {
- GNUNET_assert (0);
- return (enum CadetTunnelCState) -1;
- }
- return t->cstate;
-}
-
-
-/**
- * Get the encryption state of a tunnel.
- *
- * @param t Tunnel.
- *
- * @return Tunnel's encryption state.
- */
-enum CadetTunnelEState
-GCT_get_estate (struct CadetTunnel *t)
-{
- if (NULL == t)
- {
- GNUNET_break (0);
- return (enum CadetTunnelEState) -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
-GCT_get_channels_buffer (struct CadetTunnel *t)
-{
- struct CadetTChannel *iter;
- unsigned int buffer;
- unsigned int ch_buf;
-
- if (NULL == t->channel_head)
- {
- /* Probably getting buffer for a channel create/handshake. */
- LOG (GNUNET_ERROR_TYPE_DEBUG, " no channels, allow max\n");
- return MIN_TUNNEL_BUFFER;
- }
-
- 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;
- }
- if (MIN_TUNNEL_BUFFER > buffer)
- return MIN_TUNNEL_BUFFER;
-
- if (MAX_TUNNEL_BUFFER < buffer)
- {
- GNUNET_break (0);
- return MAX_TUNNEL_BUFFER;
- }
- 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
-GCT_get_connections_buffer (struct CadetTunnel *t)
-{
- struct CadetTConnection *iter;
- unsigned int buffer;
-
- if (GNUNET_NO == is_ready (t))
- {
- if (count_queued_data (t) >= 3)
- return 0;
- else
- return 1;
- }
-
- buffer = 0;
- for (iter = t->connection_head; NULL != iter; iter = iter->next)
- {
- if (GCC_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 *
-GCT_get_destination (struct CadetTunnel *t)
-{
- return GCP_get_id (t->peer);
-}
-
-
-/**
- * Get the tunnel's next free global channel ID.
- *
- * @param t Tunnel.
- *
- * @return GID of a channel free to use.
- */
-struct GNUNET_CADET_ChannelTunnelNumber
-GCT_get_next_ctn (struct CadetTunnel *t)
-{
- struct GNUNET_CADET_ChannelTunnelNumber ctn;
- struct GNUNET_CADET_ChannelTunnelNumber 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, GCP_get_id (t->peer));
- if (0 > result)
- mask.cn = htonl (0x40000000);
- else
- mask.cn = 0x0;
- t->next_ctn.cn |= mask.cn;
-
- while (NULL != GCT_get_channel (t, t->next_ctn))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Channel %u exists...\n",
- t->next_ctn.cn);
- t->next_ctn.cn = htonl ((ntohl (t->next_ctn.cn) + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
- t->next_ctn.cn |= mask.cn;
- }
- ctn = t->next_ctn;
- t->next_ctn.cn = (t->next_ctn.cn + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
- t->next_ctn.cn |= mask.cn;
-
- return ctn;
-}
-
-
-/**
- * Send ACK on one or more channels due to buffer in connections.
- *
- * @param t Channel which has some free buffer space.
- */
-void
-GCT_unchoke_channels (struct CadetTunnel *t)
-{
- struct CadetTChannel *iter;
- unsigned int buffer;
- unsigned int channels = GCT_count_channels (t);
- unsigned int choked_n;
- struct CadetChannel *choked[channels];
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GCT_unchoke_channels on %s\n", GCT_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);
-
- if (NULL != t->tq_head)
- send_queued_data (t);
-
- /* Get buffer space */
- buffer = GCT_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);
- GCCH_allow_client (choked[r], GCCH_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
-GCT_send_connection_acks (struct CadetTunnel *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",
- GCT_2s (t));
-
- if (NULL == t)
- {
- GNUNET_break (0);
- return;
- }
-
- if (CADET_TUNNEL_READY != t->cstate)
- return;
-
- buffer = GCT_get_channels_buffer (t);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer %u\n", buffer);
-
- /* Count connections, how many messages are already allowed */
- cs = GCT_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)
- {
- if (CADET_CONNECTION_READY != GCC_get_state (iter->c)
- || get_connection_allowed (iter) > 64 / 3)
- {
- continue;
- }
- GNUNET_assert(cs != 0);
- allow_per_connection = to_allow/cs;
- to_allow -= allow_per_connection;
- cs--;
- GCC_allow (iter->c, allow_per_connection,
- GCC_is_origin (iter->c, GNUNET_NO));
- }
-
- if (0 != to_allow)
- {
- /* Since we don't allow if it's allowed to send 64/3, this can happen. */
- LOG (GNUNET_ERROR_TYPE_DEBUG, " reminding to_allow: %u\n", to_allow);
- }
-}
-
-
-/**
- * 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
-GCT_cancel (struct CadetTunnelQueue *q)
-{
- if (NULL != q->cq)
- {
- GNUNET_assert (NULL == q->tqd);
- GCC_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);
- }
-}
-
-
-/**
- * Check if the tunnel has queued traffic.
- *
- * @param t Tunnel to check.
- *
- * @return #GNUNET_YES if there is queued traffic
- * #GNUNET_NO otherwise
- */
-int
-GCT_has_queued_traffic (struct CadetTunnel *t)
-{
- return (NULL != t->tq_head) ? GNUNET_YES : GNUNET_NO;
-}
-
-
-/**
- * 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 CadetTunnelQueue *
-GCT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
- struct CadetTunnel *t,
- struct CadetConnection *c,
- int force, GCT_sent cont, void *cont_cls)
-{
- return send_prebuilt_message (message, t, c, force, cont, cont_cls, NULL);
-}
-
-
-/**
- * Send a KX message.
- *
- * @param t Tunnel on which to send it.
- * @param force_reply Force the other peer to reply with a KX message.
- */
-void
-GCT_send_kx (struct CadetTunnel *t, int force_reply)
-{
- static struct CadetEncryptedMessageIdentifier zero;
- struct CadetConnection *c;
- struct GNUNET_CADET_TunnelKeyExchangeMessage msg;
- enum GNUNET_CADET_KX_Flags flags;
-
- LOG (GNUNET_ERROR_TYPE_INFO, "==> { KX} on %s\n", GCT_2s (t));
- if (NULL != t->ephm_h)
- {
- LOG (GNUNET_ERROR_TYPE_INFO, " already queued, nop\n");
- return;
- }
- GNUNET_assert (GNUNET_NO == GCT_is_loopback (t));
-
- c = tunnel_get_connection (t);
- if (NULL == c)
- {
- if (NULL == t->destroy_task && CADET_TUNNEL_READY == t->cstate)
- {
- GNUNET_break (0);
- GCT_debug (t, GNUNET_ERROR_TYPE_ERROR);
- }
- return;
- }
-
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX);
- flags = GNUNET_CADET_KX_FLAG_NONE;
- if (GNUNET_YES == force_reply)
- flags |= GNUNET_CADET_KX_FLAG_FORCE_REPLY;
- msg.flags = htonl (flags);
- msg.cid = *GCC_get_id (c);
- GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->kx_0, &msg.ephemeral_key);
- GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->DHRs, &msg.ratchet_key);
-
- t->ephm_h = GCC_send_prebuilt_message (&msg.header,
- UINT16_MAX,
- zero,
- c,
- GCC_is_origin (c, GNUNET_YES),
- GNUNET_YES, &ephm_sent, t);
- if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
- GCT_change_estate (t, CADET_TUNNEL_KEY_AX_SENT);
-}
-
-
-/**
- * Is the tunnel directed towards the local peer?
- *
- * @param t Tunnel.
- *
- * @return #GNUNET_YES if it is loopback.
- */
-int
-GCT_is_loopback (const struct CadetTunnel *t)
-{
- return (myid == GCP_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
-GCT_is_path_used (const struct CadetTunnel *t, const struct CadetPeerPath *p)
-{
- struct CadetTConnection *iter;
-
- for (iter = t->connection_head; NULL != iter; iter = iter->next)
- if (path_equivalent (GCC_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
-GCT_get_path_cost (const struct CadetTunnel *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 = GCC_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 *
-GCT_2s (const struct CadetTunnel *t)
-{
- if (NULL == t)
- return "(NULL)";
-
- return GCP_2s (t->peer);
-}
-
-
-/******************************************************************************/
-/***************************** INFO/DEBUG *******************************/
-/******************************************************************************/
-
-static void
-ax_debug (const struct CadetTunnelAxolotl *ax, enum GNUNET_ErrorType level)
-{
- struct GNUNET_CRYPTO_EcdhePublicKey pub;
- struct CadetTunnelSkippedKey *iter;
-
- LOG2 (level, "TTT RK \t %s\n",
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->RK));
-
- LOG2 (level, "TTT HKs \t %s\n",
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKs));
- LOG2 (level, "TTT HKr \t %s\n",
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKr));
- LOG2 (level, "TTT NHKs\t %s\n",
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->NHKs));
- LOG2 (level, "TTT NHKr\t %s\n",
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->NHKr));
-
- LOG2 (level, "TTT CKs \t %s\n",
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKs));
- LOG2 (level, "TTT CKr \t %s\n",
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKr));
-
- GNUNET_CRYPTO_ecdhe_key_get_public (ax->DHRs, &pub);
- LOG2 (level, "TTT DHRs\t %s\n",
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &pub));
- LOG2 (level, "TTT DHRr\t %s\n",
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->DHRr));
-
- LOG2 (level, "TTT Nr\t %u\tNs\t%u\n", ax->Nr, ax->Ns);
- LOG2 (level, "TTT PNs\t %u\tSkipped\t%u\n", ax->PNs, ax->skipped);
- LOG2 (level, "TTT Ratchet\t%u\n", ax->ratchet_flag);
-
- for (iter = ax->skipped_head; NULL != iter; iter = iter->next)
- {
- LOG2 (level, "TTT HK\t %s\n",
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &iter->HK));
- LOG2 (level, "TTT MK\t %s\n",
- GNUNET_i2s ((struct GNUNET_PeerIdentity *) &iter->MK));
- }
-}
-
-/**
- * Log all possible info about the tunnel state.
- *
- * @param t Tunnel to debug.
- * @param level Debug level to use.
- */
-void
-GCT_debug (const struct CadetTunnel *t, enum GNUNET_ErrorType level)
-{
- struct CadetTChannel *iter_ch;
- struct CadetTConnection *iter_c;
- int do_log;
-
- do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
- "cadet-tun",
- __FILE__, __FUNCTION__, __LINE__);
- if (0 == do_log)
- return;
-
- LOG2 (level, "TTT DEBUG TUNNEL TOWARDS %s\n", GCT_2s (t));
- LOG2 (level, "TTT cstate %s, estate %s\n",
- cstate2s (t->cstate), estate2s (t->estate));
-#if DUMP_KEYS_TO_STDERR
- ax_debug (t->ax, level);
-#endif
- LOG2 (level, "TTT tq_head %p, tq_tail %p\n", t->tq_head, t->tq_tail);
- LOG2 (level, "TTT destroy %p\n", t->destroy_task);
- LOG2 (level, "TTT channels:\n");
- for (iter_ch = t->channel_head; NULL != iter_ch; iter_ch = iter_ch->next)
- {
- GCCH_debug (iter_ch->ch, level);
- }
-
- LOG2 (level, "TTT connections:\n");
- for (iter_c = t->connection_head; NULL != iter_c; iter_c = iter_c->next)
- {
- GCC_debug (iter_c->c, level);
- }
-
- LOG2 (level, "TTT DEBUG TUNNEL END\n");
-}
-
-
-/**
- * Iterate all tunnels.
- *
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GCT_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
-GCT_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
-GCT_iterate_connections (struct CadetTunnel *t, GCT_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
-GCT_iterate_channels (struct CadetTunnel *t, GCT_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
deleted file mode 100644
index 1b56a06326..0000000000
--- a/src/cadet/gnunet-service-cadet_tunnel.h
+++ /dev/null
@@ -1,616 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2013 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, 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"
-
-#define CONNECTIONS_PER_TUNNEL 3
-
-/**
- * All the connectivity states a tunnel can be in.
- */
-enum CadetTunnelCState
-{
- /**
- * Uninitialized status, should never appear in operation.
- */
- CADET_TUNNEL_NEW,
-
- /**
- * No path to the peer known yet.
- */
- CADET_TUNNEL_SEARCHING,
-
- /**
- * Request sent, not yet answered.
- */
- CADET_TUNNEL_WAITING,
-
- /**
- * Peer connected and ready to accept data.
- */
- CADET_TUNNEL_READY,
-
- /**
- * Tunnel being shut down, don't try to keep it alive.
- */
- CADET_TUNNEL_SHUTDOWN
-};
-
-
-/**
- * All the encryption states a tunnel can be in.
- */
-enum CadetTunnelEState
-{
- /**
- * Uninitialized status, should never appear in operation.
- */
- CADET_TUNNEL_KEY_UNINITIALIZED,
-
- /**
- * Ephemeral key sent, waiting for peer's key.
- */
- CADET_TUNNEL_KEY_AX_SENT,
-
- /**
- * In OTR: 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. We DO NOT have a valid session key (either no
- * previous key or previous key expired).
- *
- *
- * In Axolotl: Key sent and received but no deciphered traffic yet.
- *
- * This means that we can send traffic (otherwise we would never complete
- * the handshake), but we don't have complete confirmation. Since the first
- * traffic MUST be a complete channel creation 3-way handshake, no payload
- * will be sent before confirmation.
- */
- CADET_TUNNEL_KEY_AX_AUTH_SENT,
-
- /**
- * Handshake completed: session key available.
- */
- CADET_TUNNEL_KEY_OK,
-
- /**
- * New ephemeral key and ping sent, waiting for pong. Unlike KEY_PING,
- * we still have a valid session key and therefore we *can* still send
- * traffic on the tunnel.
- */
- CADET_TUNNEL_KEY_REKEY
-};
-
-/**
- * Struct containing all information regarding a given peer
- */
-struct CadetTunnel;
-
-
-#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 CadetTunnelQueue;
-
-/**
- * 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
-(*GCT_sent) (void *cls,
- struct CadetTunnel *t,
- struct CadetTunnelQueue *q,
- uint16_t type, size_t size);
-
-typedef void
-(*GCT_conn_iter) (void *cls, struct CadetConnection *c);
-
-
-typedef void
-(*GCT_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
-GCT_init (const struct GNUNET_CONFIGURATION_Handle *c,
- const struct GNUNET_CRYPTO_EddsaPrivateKey *key);
-
-
-/**
- * Shut down the tunnel subsystem.
- */
-void
-GCT_shutdown (void);
-
-
-/**
- * Create a tunnel.
- *
- * @param destination Peer this tunnel is towards.
- */
-struct CadetTunnel *
-GCT_new (struct CadetPeer *destination);
-
-
-/**
- * Tunnel is empty: destroy it.
- *
- * Notifies all connections about the destruction.
- *
- * @param t Tunnel to destroy.
- */
-void
-GCT_destroy_empty (struct CadetTunnel *t);
-
-
-/**
- * Destroy tunnel if empty (no more channels).
- *
- * @param t Tunnel to destroy if empty.
- */
-void
-GCT_destroy_if_empty (struct CadetTunnel *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
-GCT_destroy (struct CadetTunnel *t);
-
-
-/**
- * Change the tunnel's connection state.
- *
- * @param t Tunnel whose connection state to change.
- * @param cstate New connection state.
- */
-void
-GCT_change_cstate (struct CadetTunnel* t, enum CadetTunnelCState cstate);
-
-
-/**
- * Change the tunnel encryption state.
- *
- * @param t Tunnel whose encryption state to change.
- * @param state New encryption state.
- */
-void
-GCT_change_estate (struct CadetTunnel* t, enum CadetTunnelEState state);
-
-
-/**
- * Add a connection to a tunnel.
- *
- * @param t Tunnel.
- * @param c Connection.
- */
-void
-GCT_add_connection (struct CadetTunnel *t, struct CadetConnection *c);
-
-
-/**
- * Remove a connection from a tunnel.
- *
- * @param t Tunnel.
- * @param c Connection.
- */
-void
-GCT_remove_connection (struct CadetTunnel *t, struct CadetConnection *c);
-
-
-/**
- * Add a channel to a tunnel.
- *
- * @param t Tunnel.
- * @param ch Channel.
- */
-void
-GCT_add_channel (struct CadetTunnel *t, struct CadetChannel *ch);
-
-
-/**
- * Remove a channel from a tunnel.
- *
- * @param t Tunnel.
- * @param ch Channel.
- */
-void
-GCT_remove_channel (struct CadetTunnel *t, struct CadetChannel *ch);
-
-
-/**
- * Search for a channel by global ID.
- *
- * @param t Tunnel containing the channel.
- * @param ctn Public channel number.
- *
- * @return channel handler, NULL if doesn't exist
- */
-struct CadetChannel *
-GCT_get_channel (struct CadetTunnel *t, struct GNUNET_CADET_ChannelTunnelNumber ctn);
-
-
-/**
- * Decrypt and process an encrypted message.
- *
- * Calls the appropriate handler for a message in a channel of a local tunnel.
- *
- * @param t Tunnel this message came on.
- * @param msg Message header.
- */
-void
-GCT_handle_encrypted (struct CadetTunnel *t,
- const struct GNUNET_CADET_TunnelEncryptedMessage *msg);
-
-
-/**
- * Handle a Key eXchange message.
- *
- * @param t Tunnel on which the message came.
- * @param msg KX message itself.
- */
-void
-GCT_handle_kx (struct CadetTunnel *t,
- const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg);
-
-
-/**
- * @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 *
-GCT_use_path (struct CadetTunnel *t, struct CadetPeerPath *p);
-
-
-/**
- * Count all created connections of a tunnel. Not necessarily ready connections!
- *
- * @param t Tunnel on which to count.
- *
- * @return Number of connections created, either being established or ready.
- */
-unsigned int
-GCT_count_any_connections (struct CadetTunnel *t);
-
-
-/**
- * Count established (ready) connections of a tunnel.
- *
- * @param t Tunnel on which to count.
- *
- * @return Number of connections.
- */
-unsigned int
-GCT_count_connections (struct CadetTunnel *t);
-
-
-/**
- * Count channels of a tunnel.
- *
- * @param t Tunnel on which to count.
- *
- * @return Number of channels.
- */
-unsigned int
-GCT_count_channels (struct CadetTunnel *t);
-
-
-/**
- * Get the connectivity state of a tunnel.
- *
- * @param t Tunnel.
- *
- * @return Tunnel's connectivity state.
- */
-enum CadetTunnelCState
-GCT_get_cstate (struct CadetTunnel *t);
-
-
-/**
- * Get the encryption state of a tunnel.
- *
- * @param t Tunnel.
- *
- * @return Tunnel's encryption state.
- */
-enum CadetTunnelEState
-GCT_get_estate (struct CadetTunnel *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
-GCT_get_channels_buffer (struct CadetTunnel *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
-GCT_get_connections_buffer (struct CadetTunnel *t);
-
-
-/**
- * Get the tunnel's destination.
- *
- * @param t Tunnel.
- *
- * @return ID of the destination peer.
- */
-const struct GNUNET_PeerIdentity *
-GCT_get_destination (struct CadetTunnel *t);
-
-
-/**
- * Get the tunnel's next free Channel ID.
- *
- * @param t Tunnel.
- *
- * @return ID of a channel free to use.
- */
-struct GNUNET_CADET_ChannelTunnelNumber
-GCT_get_next_ctn (struct CadetTunnel *t);
-
-
-/**
- * Send ACK on one or more channels due to buffer in connections.
- *
- * @param t Channel which has some free buffer space.
- */
-void
-GCT_unchoke_channels (struct CadetTunnel *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
-GCT_send_connection_acks (struct CadetTunnel *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
-GCT_cancel (struct CadetTunnelQueue *q);
-
-
-/**
- * Check if the tunnel has queued traffic.
- *
- * @param t Tunnel to check.
- *
- * @return #GNUNET_YES if there is queued traffic
- * #GNUNET_NO otherwise
- */
-int
-GCT_has_queued_traffic (struct CadetTunnel *t);
-
-/**
- * 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 CadetTunnelQueue *
-GCT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
- struct CadetTunnel *t, struct CadetConnection *c,
- int force, GCT_sent cont, void *cont_cls);
-
-
-/**
- * Send a KX message.
- *
- * @param t Tunnel on which to send it.
- * @param force_reply Force the other peer to reply with a KX message.
- */
-void
-GCT_send_kx (struct CadetTunnel *t, int force_reply);
-
-
-/**
- * Is the tunnel directed towards the local peer?
- *
- * @param t Tunnel.
- *
- * @return #GNUNET_YES if it is loopback.
- */
-int
-GCT_is_loopback (const struct CadetTunnel *t);
-
-
-/**
- * Is the tunnel using this path already?
- *
- * @param t Tunnel.
- * @param p Path.
- *
- * @return #GNUNET_YES a connection uses this path.
- */
-int
-GCT_is_path_used (const struct CadetTunnel *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
-GCT_get_path_cost (const struct CadetTunnel *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 *
-GCT_2s (const struct CadetTunnel *t);
-
-
-/**
- * Log all possible info about the tunnel state.
- *
- * @param t Tunnel to debug.
- * @param level Debug level to use.
- */
-void
-GCT_debug (const struct CadetTunnel *t, enum GNUNET_ErrorType level);
-
-
-/**
- * Iterate all tunnels.
- *
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GCT_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls);
-
-
-/**
- * Count all tunnels.
- *
- * @return Number of tunnels to remote peers kept by this peer.
- */
-unsigned int
-GCT_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
-GCT_iterate_connections (struct CadetTunnel *t, GCT_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
-GCT_iterate_channels (struct CadetTunnel *t,
- GCT_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/gnunet-service-cadet-new_tunnels.c b/src/cadet/gnunet-service-cadet_tunnels.c
index d508606293..bcdeeb4dac 100644
--- a/src/cadet/gnunet-service-cadet-new_tunnels.c
+++ b/src/cadet/gnunet-service-cadet_tunnels.c
@@ -18,7 +18,7 @@
Boston, MA 02110-1301, USA.
*/
/**
- * @file cadet/gnunet-service-cadet-new_tunnels.c
+ * @file cadet/gnunet-service-cadet_tunnels.c
* @brief Information we track per tunnel.
* @author Bartlomiej Polot
* @author Christian Grothoff
@@ -34,13 +34,12 @@
#include "gnunet_util_lib.h"
#include "gnunet_statistics_service.h"
#include "gnunet_signatures.h"
-#include "gnunet-service-cadet-new.h"
#include "cadet_protocol.h"
-#include "gnunet-service-cadet-new_channel.h"
-#include "gnunet-service-cadet-new_connection.h"
-#include "gnunet-service-cadet-new_tunnels.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_paths.h"
+#include "gnunet-service-cadet_channel.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_tunnels.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_paths.h"
#define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__)
diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.h b/src/cadet/gnunet-service-cadet_tunnels.h
index a81bc23412..4a3619ab6c 100644
--- a/src/cadet/gnunet-service-cadet-new_tunnels.h
+++ b/src/cadet/gnunet-service-cadet_tunnels.h
@@ -20,7 +20,7 @@
*/
/**
- * @file cadet/gnunet-service-cadet-new_tunnels.h
+ * @file cadet/gnunet-service-cadet_tunnels.h
* @brief Information we track per tunnel.
* @author Bartlomiej Polot
* @author Christian Grothoff
@@ -28,7 +28,7 @@
#ifndef GNUNET_SERVICE_CADET_TUNNELS_H
#define GNUNET_SERVICE_CADET_TUNNELS_H
-#include "gnunet-service-cadet-new.h"
+#include "gnunet-service-cadet.h"
#include "cadet_protocol.h"
diff --git a/src/cadet/test_cadet.c b/src/cadet/test_cadet.c
index e57c01be27..4fe43b3bf0 100644
--- a/src/cadet/test_cadet.c
+++ b/src/cadet/test_cadet.c
@@ -21,7 +21,7 @@
* @file cadet/test_cadet.c
* @author Bart Polot
* @author Christian Grothoff
- * @brief Test for the cadet service: retransmission of traffic.
+ * @brief Test for the cadet service using mq API.
*/
#include <stdio.h>
#include "platform.h"
@@ -32,9 +32,20 @@
/**
- * How many messages to send
+ * Ugly workaround to unify data handlers on incoming and outgoing channels.
*/
-#define TOTAL_PACKETS 500 /* Cannot exceed 64k! */
+struct CadetTestChannelWrapper
+{
+ /**
+ * Channel pointer.
+ */
+ struct GNUNET_CADET_Channel *ch;
+};
+
+/**
+ * How many messages to send by default.
+ */
+#define TOTAL_PACKETS 500 /* Cannot exceed 64k! */
/**
* How long until we give up on connecting the peers?
@@ -42,7 +53,7 @@
#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
/**
- * Time to wait for stuff that should be rather fast
+ * Time to wait by default for stuff that should be rather fast.
*/
#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
@@ -73,6 +84,16 @@ static char *test_name;
static int test_backwards = GNUNET_NO;
/**
+ * How many packets to send.
+ */
+static unsigned int total_packets;
+
+/**
+ * Time to wait for fast operations.
+ */
+static struct GNUNET_TIME_Relative short_time;
+
+/**
* How many events have happened
*/
static int ok;
@@ -83,9 +104,9 @@ static int ok;
static int ok_goal;
/**
- * Size of each test packet
+ * Size of each test packet's payload
*/
-static size_t size_payload = sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t);
+static size_t size_payload = sizeof (uint32_t);
/**
* Operation to get peer ids.
@@ -158,9 +179,9 @@ static struct GNUNET_SCHEDULER_Task *disconnect_task;
static struct GNUNET_SCHEDULER_Task *test_task;
/**
- * Task runnining #data_task().
+ * Task runnining #send_next_msg().
*/
-static struct GNUNET_SCHEDULER_Task *data_job;
+static struct GNUNET_SCHEDULER_Task *send_next_msg_task;
/**
* Cadet handle for the root peer
@@ -175,7 +196,7 @@ static struct GNUNET_CADET_Handle *h2;
/**
* Channel handle for the root peer
*/
-static struct GNUNET_CADET_Channel *ch;
+static struct GNUNET_CADET_Channel *outgoing_ch;
/**
* Channel handle for the dest peer
@@ -183,17 +204,6 @@ static struct GNUNET_CADET_Channel *ch;
static struct GNUNET_CADET_Channel *incoming_ch;
/**
- * Transmit handle for root data calls
- */
-static struct GNUNET_CADET_TransmitHandle *th;
-
-/**
- * Transmit handle for root data calls
- */
-static struct GNUNET_CADET_TransmitHandle *incoming_th;
-
-
-/**
* Time we started the data transmission (after channel has been established
* and initilized).
*/
@@ -225,20 +235,26 @@ static unsigned int ka_received;
static unsigned int msg_dropped;
+/******************************************************************************/
+
+
+/******************************************************************************/
+
+
/**
- * Get the client number considered as the "target" or "receiver", depending on
+ * Get the channel considered as the "target" or "receiver", depending on
* the test type and size.
*
- * @return Peer # of the target client, either 0 (for backward tests) or
- * the last peer in the line (for other tests).
+ * @return Channel handle of the target client, either 0 (for backward tests)
+ * or the last peer in the line (for other tests).
*/
-static unsigned int
-get_expected_target ()
+static struct GNUNET_CADET_Channel *
+get_target_channel ()
{
if (SPEED == test && GNUNET_YES == test_backwards)
- return 0;
+ return outgoing_ch;
else
- return peers_requested - 1;
+ return incoming_ch;
}
@@ -251,18 +267,15 @@ 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);
+ 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
+ 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),
+ total_packets * 1000.0 / (total_time.rel_value_us / 1000),
"packets/s");
}
@@ -281,29 +294,19 @@ disconnect_cadet_peers (void *cls)
disconnect_task = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "disconnecting cadet service of peers, called from line %ld\n",
- line);
+ "disconnecting cadet service of peers, called from line %ld\n",
+ line);
for (i = 0; i < 2; i++)
{
GNUNET_TESTBED_operation_done (t_op[i]);
}
- if (NULL != ch)
+ if (NULL != outgoing_ch)
{
- if (NULL != th)
- {
- GNUNET_CADET_notify_transmit_ready_cancel (th);
- th = NULL;
- }
- GNUNET_CADET_channel_destroy (ch);
- ch = NULL;
+ GNUNET_CADET_channel_destroy (outgoing_ch);
+ outgoing_ch = NULL;
}
if (NULL != incoming_ch)
{
- if (NULL != incoming_th)
- {
- GNUNET_CADET_notify_transmit_ready_cancel (incoming_th);
- incoming_th = NULL;
- }
GNUNET_CADET_channel_destroy (incoming_ch);
incoming_ch = NULL;
}
@@ -322,10 +325,10 @@ static void
shutdown_task (void *cls)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n");
- if (NULL != data_job)
+ if (NULL != send_next_msg_task)
{
- GNUNET_SCHEDULER_cancel (data_job);
- data_job = NULL;
+ GNUNET_SCHEDULER_cancel (send_next_msg_task);
+ send_next_msg_task = NULL;
}
if (NULL != test_task)
{
@@ -335,8 +338,8 @@ shutdown_task (void *cls)
if (NULL != disconnect_task)
{
GNUNET_SCHEDULER_cancel (disconnect_task);
- disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
- (void *) __LINE__);
+ disconnect_task =
+ GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) __LINE__);
}
}
@@ -351,17 +354,11 @@ shutdown_task (void *cls)
* operation has executed successfully.
*/
static void
-stats_cont (void *cls,
- struct GNUNET_TESTBED_Operation *op,
- const char *emsg)
+stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- " KA sent: %u, KA received: %u\n",
- ka_sent,
- ka_received);
- if ( (KEEPALIVE == test) &&
- ( (ka_sent < 2) ||
- (ka_sent > ka_received + 1)) )
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, " KA sent: %u, KA received: %u\n",
+ ka_sent, ka_received);
+ if ((KEEPALIVE == test) && ((ka_sent < 2) || (ka_sent > ka_received + 1)))
{
GNUNET_break (0);
ok--;
@@ -370,8 +367,7 @@ stats_cont (void *cls,
if (NULL != disconnect_task)
GNUNET_SCHEDULER_cancel (disconnect_task);
- disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
- cls);
+ disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, cls);
}
@@ -387,11 +383,8 @@ stats_cont (void *cls,
* @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,
+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";
@@ -401,19 +394,15 @@ stats_iterator (void *cls,
uint32_t i;
i = GNUNET_TESTBED_get_index (peer);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "STATS PEER %u - %s [%s]: %llu\n",
- i,
- subsystem,
- name,
- (unsigned long long) value);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "STATS PEER %u - %s [%s]: %llu\n", i,
+ subsystem, name, (unsigned long long) value);
if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i)
ka_sent = value;
- if (0 == strncmp(s_recv, name, strlen (s_recv)) && peers_requested - 1 == i)
+ if (0 == strncmp (s_recv, name, strlen (s_recv)) && peers_requested - 1 == i)
ka_received = value;
- if (0 == strncmp(rdrops, name, strlen (rdrops)))
+ if (0 == strncmp (rdrops, name, strlen (rdrops)))
msg_dropped += value;
- if (0 == strncmp(cdrops, name, strlen (cdrops)))
+ if (0 == strncmp (cdrops, name, strlen (cdrops)))
msg_dropped += value;
return GNUNET_OK;
@@ -423,7 +412,7 @@ stats_iterator (void *cls,
/**
* Task to gather all statistics.
*
- * @param cls Closure (NULL).
+ * @param cls Closure (line from which the task was scheduled).
*/
static void
gather_stats_and_exit (void *cls)
@@ -432,21 +421,20 @@ gather_stats_and_exit (void *cls)
disconnect_task = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "gathering statistics from line %d\n",
- (int) l);
- if (NULL != ch)
+ "gathering statistics from line %ld\n",
+ l);
+ if (NULL != outgoing_ch)
{
- if (NULL != th)
- {
- GNUNET_CADET_notify_transmit_ready_cancel (th);
- th = NULL;
- }
- GNUNET_CADET_channel_destroy (ch);
- ch = NULL;
+ GNUNET_CADET_channel_destroy (outgoing_ch);
+ outgoing_ch = NULL;
}
- stats_op = GNUNET_TESTBED_get_statistics (peers_running, testbed_peers,
- "cadet", NULL,
- &stats_iterator, stats_cont, cls);
+ stats_op = GNUNET_TESTBED_get_statistics (peers_running,
+ testbed_peers,
+ "cadet",
+ NULL,
+ &stats_iterator,
+ stats_cont,
+ cls);
}
@@ -462,163 +450,151 @@ abort_test (long line)
if (NULL != disconnect_task)
{
GNUNET_SCHEDULER_cancel (disconnect_task);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Aborting test from %ld\n", line);
- disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
- (void *) line);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Aborting test from %ld\n", line);
+ 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 request a new data transmission.
+ * Send a message on the channel with the appropriate size and payload.
+ *
+ * Update the appropriate *_sent counter.
*
- * @param cls Closure (peer #).
+ * @param channel Channel to send the message on.
*/
static void
-data_task (void *cls)
+send_test_message (struct GNUNET_CADET_Channel *channel)
{
- struct GNUNET_CADET_Channel *channel;
- static struct GNUNET_CADET_TransmitHandle **pth;
- long src;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_MessageHeader *msg;
+ uint32_t *data;
+ int payload;
+ int size;
- data_job = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data task\n");
- if (GNUNET_YES == test_backwards)
- {
- channel = incoming_ch;
- pth = &incoming_th;
- src = peers_requested - 1;
- }
- else
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending test message on channel %p\n",
+ channel);
+ size = size_payload;
+ if (GNUNET_NO == initialized)
{
- channel = ch;
- pth = &th;
- src = 0;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending INITIALIZER\n");
+ size += 1000;
+ payload = data_sent;
+ if (SPEED_ACK == test) // FIXME unify SPEED_ACK with an initializer
+ data_sent++;
}
-
- GNUNET_assert (NULL != channel);
- GNUNET_assert (NULL == *pth);
-
- *pth = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
- GNUNET_TIME_UNIT_FOREVER_REL,
- size_payload + data_sent,
- &tmt_rdy, (void *) src);
- if (NULL == *pth)
+ else if (SPEED == test || SPEED_ACK == test)
{
- unsigned long i = (unsigned long) cls;
-
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Retransmission\n");
- if (0 == i)
+ if (get_target_channel() == channel)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, " in 1 ms\n");
- data_job = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
- &data_task, (void *) 1L);
+ payload = ack_sent;
+ size += ack_sent;
+ ack_sent++;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending ACK %u [%d bytes]\n",
+ payload, size);
}
else
{
- i++;
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "in %llu ms\n",
- (unsigned long long) i);
- data_job = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
- i),
- &data_task, (void *) i);
+ payload = data_sent;
+ size += data_sent;
+ data_sent++;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending DATA %u [%d bytes]\n",
+ data_sent, size);
}
}
-}
+ else if (FORWARD == test)
+ {
+ payload = ack_sent;
+ }
+ else if (P2P_SIGNAL == test)
+ {
+ payload = data_sent;
+ }
+ else
+ {
+ GNUNET_assert (0);
+ }
+ env = GNUNET_MQ_msg_extra (msg, size, GNUNET_MESSAGE_TYPE_DUMMY);
+ data = (uint32_t *) &msg[1];
+ *data = htonl (payload);
+ GNUNET_MQ_send (GNUNET_CADET_get_mq (channel), env);
+}
/**
- * Transmit ready callback
+ * Task to request a new data transmission in a SPEED test, without waiting
+ * for previous messages to be sent/arrrive.
*
- * @param cls Closure (peer # which is sending the data).
- * @param size Size of the buffer we have.
- * @param buf Buffer to copy data to.
+ * @param cls Closure (unused).
*/
-static size_t
-tmt_rdy (void *cls, size_t size, void *buf)
+static void
+send_next_msg (void *cls)
{
- struct GNUNET_MessageHeader *msg = buf;
- size_t msg_size;
- uint32_t *data;
- long id = (long) cls;
- unsigned int counter;
+ struct GNUNET_CADET_Channel *channel;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "tmt_rdy on %ld, filling buffer\n",
- id);
- if (0 == id)
- th = NULL;
- else if ((peers_requested - 1) == id)
- incoming_th = NULL;
- else
- GNUNET_assert (0);
- counter = get_expected_target () == id ? ack_sent : data_sent;
- msg_size = size_payload + counter;
- GNUNET_assert (msg_size > sizeof (struct GNUNET_MessageHeader));
- if ( (size < msg_size) ||
- (NULL == buf) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "size %u, buf %p, data_sent %u, ack_received %u\n",
- (unsigned int) size,
- buf,
- data_sent,
- ack_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 (msg_size);
- msg->type = htons (GNUNET_MESSAGE_TYPE_DUMMY);
- data = (uint32_t *) &msg[1];
- *data = htonl (counter);
- if (GNUNET_NO == initialized)
+ send_next_msg_task = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending next message: %d\n", data_sent);
+
+ channel = GNUNET_YES == test_backwards ? incoming_ch : outgoing_ch;
+ GNUNET_assert (NULL != channel);
+ GNUNET_assert (SPEED == test);
+ send_test_message (channel);
+ if (data_sent < total_packets)
{
+ /* SPEED test: Send all messages as soon as possible */
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "sending initializer\n");
- msg_size = size_payload + 1000;
- msg->size = htons (msg_size);
- if (SPEED_ACK == test)
- data_sent++;
+ "Scheduling message %d\n",
+ data_sent + 1);
+ send_next_msg_task =
+ GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_SECONDS,
+ &send_next_msg,
+ NULL);
}
- else if ( (SPEED == test) ||
- (SPEED_ACK == test) )
+}
+
+
+/**
+ * Every few messages cancel the timeout task and re-schedule it again, to
+ * avoid timing out when traffic keeps coming.
+ *
+ * @param line Code line number to log if a timeout occurs.
+ */
+static void
+reschedule_timeout_task (long line)
+{
+ if ((ok % 10) == 0)
{
- if (get_expected_target() == id)
- ack_sent++;
- else
- data_sent++;
- counter++;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- " Sent message %u size %u\n",
- counter,
- (unsigned int) msg_size);
- if ( (data_sent < TOTAL_PACKETS) &&
- (SPEED == test) )
+ if (NULL != disconnect_task)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- " Scheduling message %d\n",
- counter + 1);
- data_job = GNUNET_SCHEDULER_add_now (&data_task, NULL);
+ " reschedule timeout every 10 messages\n");
+ GNUNET_SCHEDULER_cancel (disconnect_task);
+ disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
+ &gather_stats_and_exit,
+ (void *) line);
}
}
+}
- return msg_size;
+
+/**
+ * Check if payload is sane (size contains payload).
+ *
+ * @param cls should match #ch
+ * @param message The actual message.
+ * @return #GNUNET_OK to keep the channel open,
+ * #GNUNET_SYSERR to close it (signal serious error).
+ */
+static int
+check_data (void *cls, const struct GNUNET_MessageHeader *message)
+{
+ if (sizeof (struct GNUNET_MessageHeader) >= ntohs (message->size))
+ return GNUNET_SYSERR;
+ return GNUNET_OK; /* all is well-formed */
}
@@ -626,75 +602,50 @@ tmt_rdy (void *cls, size_t size, void *buf)
* Function is called whenever a message is received.
*
* @param cls closure (set from GNUNET_CADET_connect(), peer number)
- * @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)
+static void
+handle_data (void *cls, const struct GNUNET_MessageHeader *message)
{
- struct GNUNET_CADET_TransmitHandle **pth;
- long client = (long) cls;
- long expected_target_client;
+ struct CadetTestChannelWrapper *ch = cls;
+ struct GNUNET_CADET_Channel *channel = ch->ch;
uint32_t *data;
uint32_t payload;
- unsigned int counter;
+ int *counter;
ok++;
- counter = get_expected_target () == client ? data_received : ack_received;
-
GNUNET_CADET_receive_done (channel);
+ counter = get_target_channel () == channel ? &data_received : &ack_received;
- if ((ok % 10) == 0)
+ reschedule_timeout_task ((long) __LINE__);
+
+ if (channel == outgoing_ch)
{
- if (NULL != disconnect_task)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- " reschedule timeout\n");
- GNUNET_SCHEDULER_cancel (disconnect_task);
- disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
- &gather_stats_and_exit,
- (void *) __LINE__);
- }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message.\n");
}
-
- switch (client)
+ else if (channel == incoming_ch)
{
- case 0L:
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message!\n");
- GNUNET_assert (channel == ch);
- pth = &th;
- break;
- case 1L:
- case 4L:
- GNUNET_assert (client == peers_requested - 1);
- GNUNET_assert (channel == incoming_ch);
- pth = &incoming_th;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Leaf client %ld got a message.\n",
- client);
- break;
- default:
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Client %ld not valid.\n", client);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Leaf client got a message.\n");
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown channel %p.\n", channel);
GNUNET_assert (0);
}
+
GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: (%d/%d)\n", ok, ok_goal);
data = (uint32_t *) &message[1];
payload = ntohl (*data);
- if (payload == counter)
+ if (payload == *counter)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO, " payload as expected: %u\n", payload);
}
else
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " payload %u, expected: %u\n",
- payload, counter);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ " payload %u, expected: %u\n",
+ payload, *counter);
}
- expected_target_client = get_expected_target ();
if (GNUNET_NO == initialized)
{
@@ -702,189 +653,152 @@ data_callback (void *cls,
start_time = GNUNET_TIME_absolute_get ();
if (SPEED == test)
{
- GNUNET_assert (peers_requested - 1 == client);
- data_job = GNUNET_SCHEDULER_add_now (&data_task, NULL);
- return GNUNET_OK;
+ GNUNET_assert (incoming_ch == channel);
+ send_next_msg_task = GNUNET_SCHEDULER_add_now (&send_next_msg, NULL);
+ return;
}
}
- counter++;
- if (client == expected_target_client) /* Normally 4 */
+ (*counter)++;
+ if (get_target_channel () == channel) /* Got "data" */
{
- data_received++;
GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received data %u\n", data_received);
if (SPEED != test || (ok_goal - 2) == ok)
{
/* Send ACK */
- GNUNET_assert (NULL == *pth);
- *pth = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
- GNUNET_TIME_UNIT_FOREVER_REL,
- size_payload + ack_sent,
- &tmt_rdy, (void *) client);
- return GNUNET_OK;
+ send_test_message (channel);
+ return;
}
else
{
- if (data_received < TOTAL_PACKETS)
- return GNUNET_OK;
+ if (data_received < total_packets)
+ return;
}
}
- else /* Normally 0 */
+ else /* Got "ack" */
{
if (SPEED_ACK == test || SPEED == test)
{
- ack_received++;
GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received ack %u\n", ack_received);
- /* send more data */
- GNUNET_assert (NULL == *pth);
- *pth = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
- GNUNET_TIME_UNIT_FOREVER_REL,
- size_payload + data_sent,
- &tmt_rdy, (void *) client);
- if (ack_received < TOTAL_PACKETS && SPEED != test)
- return GNUNET_OK;
+ /* Send more data */
+ send_test_message (channel);
+ if (ack_received < total_packets && SPEED != test)
+ return;
if (ok == 2 && SPEED == test)
- return GNUNET_OK;
- show_end_data();
+ return;
+ show_end_data ();
}
if (test == P2P_SIGNAL)
{
- if (NULL != incoming_th)
- {
- GNUNET_CADET_notify_transmit_ready_cancel (incoming_th);
- incoming_th = NULL;
- }
GNUNET_CADET_channel_destroy (incoming_ch);
incoming_ch = NULL;
}
else
{
- if (NULL != th)
- {
- GNUNET_CADET_notify_transmit_ready_cancel (th);
- th = NULL;
- }
- GNUNET_CADET_channel_destroy (ch);
- ch = NULL;
+ GNUNET_CADET_channel_destroy (outgoing_ch);
+ outgoing_ch = NULL;
}
}
-
- return GNUNET_OK;
}
/**
- * Data handlers for every message type of CADET's payload.
- * {callback_function, message_type, size_expected}
- */
-static struct GNUNET_CADET_MessageHandler handlers[] = {
- {&data_callback,
- GNUNET_MESSAGE_TYPE_DUMMY,
- sizeof (struct GNUNET_MessageHeader)},
- {NULL, 0, 0}
-};
-
-
-/**
- * Method called whenever another peer has added us to a channel
- * the other peer initiated.
+ * Method called whenever a peer connects to a port in MQ-based CADET.
*
- * @param cls Closure.
+ * @param cls Closure from #GNUNET_CADET_open_porT (peer # as long).
* @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).
+ * @param source Peer that started this channel.
+ * @return Closure for the incoming @a channel. It's given to:
+ * - The #GNUNET_CADET_DisconnectEventHandler (given to
+ * #GNUNET_CADET_open_porT) when the channel dies.
+ * - Each the #GNUNET_MQ_MessageCallback handlers for each message
+ * received on the @a channel.
*/
static void *
-incoming_channel (void *cls,
- struct GNUNET_CADET_Channel *channel,
- const struct GNUNET_PeerIdentity *initiator,
- const struct GNUNET_HashCode *port,
- enum GNUNET_CADET_ChannelOption options)
+connect_handler (void *cls, struct GNUNET_CADET_Channel *channel,
+ const struct GNUNET_PeerIdentity *source)
{
+ struct CadetTestChannelWrapper *ch;
+ long peer = (long) cls;
+
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Incoming channel from %s to peer %d:%s\n",
- GNUNET_i2s (initiator),
- (int) (long) cls, GNUNET_h2s (port));
+ "Incoming channel from %s to %ld: %p\n",
+ GNUNET_i2s (source), peer, channel);
ok++;
GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
- if ((long) cls == peers_requested - 1)
+ if (peer == peers_requested - 1)
{
if (NULL != incoming_ch)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Duplicate incoming channel for client %lu\n",
- (long) cls);
- GNUNET_break(0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Duplicate incoming channel for client %lu\n", (long) cls);
+ GNUNET_assert (0);
}
incoming_ch = channel;
}
else
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Incoming channel for unexpected peer #%lu\n",
- (long) cls);
- GNUNET_break (0);
+ "Incoming channel for unexpected peer #%lu\n", (long) cls);
+ GNUNET_assert (0);
}
if (NULL != disconnect_task)
{
GNUNET_SCHEDULER_cancel (disconnect_task);
- disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
+ disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
&gather_stats_and_exit,
(void *) __LINE__);
}
- return NULL;
+ /* TODO: cannot return channel as-is, in order to unify the data handlers */
+ ch = GNUNET_new (struct CadetTestChannelWrapper);
+ ch->ch = channel;
+
+ return ch;
}
/**
- * Function called whenever an inbound channel is destroyed. Should clean up
- * any associated state.
+ * Function called whenever an MQ-channel is destroyed, even if the destruction
+ * was requested by #GNUNET_CADET_channel_destroy.
+ * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
*
- * @param cls closure (set from GNUNET_CADET_connect, peer number)
- * @param channel connection to the other end (henceforth invalid)
- * @param channel_ctx place where local state associated
- * with the channel is stored
+ * It should clean up any associated state, including cancelling any pending
+ * transmission on this channel.
+ *
+ * @param cls Channel closure (channel wrapper).
+ * @param channel Connection to the other end (henceforth invalid).
*/
static void
-channel_cleaner (void *cls,
- const struct GNUNET_CADET_Channel *channel,
- void *channel_ctx)
+disconnect_handler (void *cls, const struct GNUNET_CADET_Channel *channel)
{
- long i = (long) cls;
+ struct CadetTestChannelWrapper *ch_w = cls;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Incoming channel disconnected at peer %ld\n",
- i);
- if (peers_running - 1 == i)
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Channel disconnected\n");
+ GNUNET_assert (ch_w->ch == channel);
+ if (channel == incoming_ch)
{
ok++;
- GNUNET_break (channel == incoming_ch);
incoming_ch = NULL;
}
- else if (0L == i)
+ else if (outgoing_ch == channel
+ )
{
if (P2P_SIGNAL == test)
{
ok++;
}
- GNUNET_break (channel == ch);
- ch = NULL;
+ outgoing_ch = NULL;
}
else
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Unknown peer! %d\n",
- (int) i);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unknown channel! %p\n", channel);
GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
if (NULL != disconnect_task)
{
GNUNET_SCHEDULER_cancel (disconnect_task);
- disconnect_task = GNUNET_SCHEDULER_add_now (&gather_stats_and_exit,
- (void *) __LINE__);
+ disconnect_task =
+ GNUNET_SCHEDULER_add_now (&gather_stats_and_exit, (void *) __LINE__);
}
}
@@ -898,13 +812,20 @@ channel_cleaner (void *cls,
* @param cls Closure (unused).
*/
static void
-do_test (void *cls)
+start_test (void *cls)
{
+ struct GNUNET_MQ_MessageHandler handlers[] = {
+ GNUNET_MQ_hd_var_size (data,
+ GNUNET_MESSAGE_TYPE_DUMMY,
+ struct GNUNET_MessageHeader,
+ NULL),
+ GNUNET_MQ_handler_end ()
+ };
+ struct CadetTestChannelWrapper *ch;
enum GNUNET_CADET_ChannelOption flags;
test_task = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "do_test\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "start_test\n");
if (NULL != disconnect_task)
{
GNUNET_SCHEDULER_cancel (disconnect_task);
@@ -918,30 +839,33 @@ do_test (void *cls)
flags |= GNUNET_CADET_OPTION_RELIABLE;
}
- ch = GNUNET_CADET_channel_create (h1,
- NULL,
- p_id[1],
- &port,
- flags);
+ ch = GNUNET_new (struct CadetTestChannelWrapper);
+ outgoing_ch = GNUNET_CADET_channel_creatE (h1,
+ ch,
+ p_id[1],
+ &port,
+ flags,
+ NULL,
+ &disconnect_handler,
+ handlers);
+
+ ch->ch = outgoing_ch;
- disconnect_task
- = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
- &gather_stats_and_exit,
- (void *) __LINE__);
+ disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
+ &gather_stats_and_exit,
+ (void *) __LINE__);
if (KEEPALIVE == test)
- return; /* Don't send any data. */
+ return; /* Don't send any data. */
+
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending data initializer...\n");
data_received = 0;
data_sent = 0;
ack_received = 0;
ack_sent = 0;
- th = GNUNET_CADET_notify_transmit_ready (ch,
- GNUNET_NO,
- GNUNET_TIME_UNIT_FOREVER_REL,
- size_payload + 1000,
- &tmt_rdy, (void *) 0L);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending data initializer on channel %p...\n",
+ outgoing_ch);
+ send_test_message (outgoing_ch);
}
@@ -955,35 +879,26 @@ do_test (void *cls)
* 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)
+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);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ID callback for %ld\n", i);
- if ( (NULL == pinfo) ||
- (NULL != emsg) )
+ if ((NULL == pinfo) || (NULL != emsg))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "pi_cb: %s\n", 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]));
+ 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);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n");
+ test_task = GNUNET_SCHEDULER_add_now (&start_test, NULL);
}
@@ -994,7 +909,7 @@ pi_cb (void *cls,
* @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.
+ * @param cadets Handle to each of the CADETs of the peers.
*/
static void
tmain (void *cls,
@@ -1011,16 +926,18 @@ tmain (void *cls,
testbed_peers = peers;
h1 = cadets[0];
h2 = cadets[num_peers - 1];
- disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
+ disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
&disconnect_cadet_peers,
(void *) __LINE__);
GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0],
GNUNET_TESTBED_PIT_IDENTITY,
- &pi_cb, (void *) 0L);
+ &pi_cb,
+ (void *) 0L);
t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1],
GNUNET_TESTBED_PIT_IDENTITY,
- &pi_cb, (void *) 1L);
+ &pi_cb,
+ (void *) 1L);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n");
}
@@ -1031,16 +948,42 @@ tmain (void *cls,
int
main (int argc, char *argv[])
{
+ struct GNUNET_MQ_MessageHandler handlers[] = {
+ GNUNET_MQ_hd_var_size (data,
+ GNUNET_MESSAGE_TYPE_DUMMY,
+ struct GNUNET_MessageHeader,
+ NULL),
+ GNUNET_MQ_handler_end ()
+ };
+
initialized = GNUNET_NO;
static const struct GNUNET_HashCode *ports[2];
const char *config_file;
char port_id[] = "test port";
- GNUNET_CRYPTO_hash (port_id, sizeof (port_id), &port);
+
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'t', "time", "short_time",
+ gettext_noop ("set short timeout"),
+ GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &short_time},
+ {'m', "messages", "NUM_MESSAGES",
+ gettext_noop ("set number of messages to send"),
+ GNUNET_YES, &GNUNET_GETOPT_set_uint, &total_packets},
+
+ GNUNET_GETOPT_OPTION_END
+ };
GNUNET_log_setup ("test", "DEBUG", NULL);
- config_file = "test_cadet.conf";
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start\n");
+ total_packets = TOTAL_PACKETS;
+ short_time = SHORT_TIME;
+ if (-1 == GNUNET_GETOPT_run (argv[0], options, argc, argv))
+ {
+ FPRINTF (stderr, "test failed: problem with CLI parameters\n");
+ exit (1);
+ }
+
+ config_file = "test_cadet.conf";
+ GNUNET_CRYPTO_hash (port_id, sizeof (port_id), &port);
/* Find out requested size */
if (strstr (argv[0], "_2_") != NULL)
@@ -1078,11 +1021,11 @@ main (int argc, char *argv[])
{
/* Test is supposed to generate the following callbacks:
* 1 incoming channel (@dest)
- * TOTAL_PACKETS received data packet (@dest)
- * TOTAL_PACKETS received data packet (@orig)
+ * total_packets received data packet (@dest)
+ * total_packets received data packet (@orig)
* 1 received channel destroy (@dest)
*/
- ok_goal = TOTAL_PACKETS * 2 + 2;
+ ok_goal = total_packets * 2 + 2;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n");
test = SPEED_ACK;
test_name = "speed ack";
@@ -1092,11 +1035,11 @@ main (int argc, char *argv[])
/* Test is supposed to generate the following callbacks:
* 1 incoming channel (@dest)
* 1 initial packet (@dest)
- * TOTAL_PACKETS received data packet (@dest)
+ * total_packets received data packet (@dest)
* 1 received data packet (@orig)
* 1 received channel destroy (@dest)
*/
- ok_goal = TOTAL_PACKETS + 4;
+ ok_goal = total_packets + 4;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n");
if (strstr (argv[0], "_reliable") != NULL)
{
@@ -1137,22 +1080,22 @@ main (int argc, char *argv[])
p_ids = 0;
ports[0] = &port;
ports[1] = NULL;
- GNUNET_CADET_TEST_run ("test_cadet_small",
- config_file,
- peers_requested,
- &tmain,
- NULL, /* tmain cls */
- &incoming_channel,
- &channel_cleaner,
- handlers,
- ports);
+ GNUNET_CADET_TEST_ruN ("test_cadet_small",
+ config_file,
+ peers_requested,
+ &tmain,
+ NULL, /* tmain cls */
+ &connect_handler,
+ NULL,
+ &disconnect_handler,
+ handlers,
+ ports);
if (NULL != strstr (argv[0], "_reliable"))
- msg_dropped = 0; /* dropped should be retransmitted */
+ msg_dropped = 0; /* dropped should be retransmitted */
if (ok_goal > ok - msg_dropped)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "FAILED! (%d/%d)\n", ok, ok_goal);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "FAILED! (%d/%d)\n", ok, ok_goal);
return 1;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n");
diff --git a/src/cadet/test_cadet_local.c b/src/cadet/test_cadet_local.c
deleted file mode 100644
index 2b915ab813..0000000000
--- a/src/cadet/test_cadet_local.c
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2011 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, 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 struct GNUNET_SCHEDULER_Task *abort_task;
-
-static struct GNUNET_SCHEDULER_Task *connect_task;
-
-static struct GNUNET_CADET_TransmitHandle *mth;
-
-
-/**
- * Connect to other client and send data
- *
- * @param cls Closue (unused).
- */
-static void
-do_connect (void *cls);
-
-
-/**
- * Shutdown nicely
- */
-static void
-do_shutdown (void *cls)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "shutdown\n");
- if (NULL != abort_task)
- {
- GNUNET_SCHEDULER_cancel (abort_task);
- abort_task = NULL;
- }
- if (NULL != ch)
- {
- GNUNET_CADET_channel_destroy (ch);
- ch = NULL;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Disconnect client 1\n");
- if (NULL != cadet_peer_1)
- {
- GNUNET_CADET_disconnect (cadet_peer_1);
- cadet_peer_1 = NULL;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Disconnect client 2\n");
- if (NULL != cadet_peer_2)
- {
- GNUNET_CADET_disconnect (cadet_peer_2);
- cadet_peer_2 = NULL;
- }
- if (NULL != connect_task)
- {
- GNUNET_SCHEDULER_cancel (connect_task);
- connect_task = NULL;
- }
-}
-
-
-/**
- * Something went wrong and timed out. Kill everything and set error flag
- */
-static void
-do_abort (void *cls)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ABORT\n");
- result = GNUNET_SYSERR;
- abort_task = NULL;
- GNUNET_SCHEDULER_shutdown ();
-}
-
-
-/**
- * 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;
- GNUNET_SCHEDULER_shutdown ();
- 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,
- const struct GNUNET_HashCode *port,
- enum GNUNET_CADET_ChannelOption options)
-{
- long id = (long) cls;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "received incoming channel on peer %d, port %s\n",
- (int) id,
- GNUNET_h2s (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 (channel == ch)
- ch = NULL;
- if (GNUNET_NO == got_data)
- {
- if (NULL == connect_task)
- connect_task
- = 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).
- */
-static void
-do_connect (void *cls)
-{
- struct GNUNET_PeerIdentity id;
-
- connect_task = NULL;
- 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, GC_u2h (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)
-{
- me = peer;
- GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
- NULL);
- 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 */
- &channel_end, /* channel end hndlr */
- handlers1); /* traffic handlers */
- cadet_peer_2 = GNUNET_CADET_connect (cfg, /* configuration */
- (void *) 2L, /* cls */
- &channel_end, /* channel end hndlr */
- handlers2); /* traffic handlers */
-
- if ( (NULL == cadet_peer_1) ||
- (NULL == cadet_peer_2) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Couldn't connect to cadet :(\n");
- result = GNUNET_SYSERR;
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- GNUNET_CADET_open_port (cadet_peer_2,
- GC_u2h (1),
- &inbound_channel,
- (void *) 2L);
- if (NULL == connect_task)
- connect_task
- = 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_new.c b/src/cadet/test_cadet_new.c
deleted file mode 100644
index 374e86bf3c..0000000000
--- a/src/cadet/test_cadet_new.c
+++ /dev/null
@@ -1,1105 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2011, 2017 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/test_cadet_mq.c
- * @author Bart Polot
- * @author Christian Grothoff
- * @brief Test for the cadet service using mq API.
- */
-#include <stdio.h>
-#include "platform.h"
-#include "cadet_test_lib_new.h"
-#include "gnunet_cadet_service.h"
-#include "gnunet_statistics_service.h"
-#include <gauger.h>
-
-
-/**
- * Ugly workaround to unify data handlers on incoming and outgoing channels.
- */
-struct CadetTestChannelWrapper
-{
- /**
- * Channel pointer.
- */
- struct GNUNET_CADET_Channel *ch;
-};
-
-/**
- * How many messages to send by default.
- */
-#define TOTAL_PACKETS 500 /* Cannot exceed 64k! */
-
-/**
- * How long until we give up on connecting the peers?
- */
-#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
-
-/**
- * Time to wait by default for stuff that should be rather fast.
- */
-#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
-
-/**
- * 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
- */
-static 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 packets to send.
- */
-static unsigned int total_packets;
-
-/**
- * Time to wait for fast operations.
- */
-static struct GNUNET_TIME_Relative short_time;
-
-/**
- * How many events have happened
- */
-static int ok;
-
-/**
- * Number of events expected to conclude the test successfully.
- */
-static int ok_goal;
-
-/**
- * Size of each test packet's payload
- */
-static size_t size_payload = sizeof (uint32_t);
-
-/**
- * Operation to get peer ids.
- */
-static struct GNUNET_TESTBED_Operation *t_op[2];
-
-/**
- * Peer ids.
- */
-static struct GNUNET_PeerIdentity *p_id[2];
-
-/**
- * Port ID
- */
-static struct GNUNET_HashCode port;
-
-/**
- * Peer ids counter.
- */
-static 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 acknowledgements sent.
- */
-static int ack_sent;
-
-/**
- * Number of payload packed explicitly (app level) acknowledged.
- */
-static int ack_received;
-
-/**
- * Total number of peers asked to run.
- */
-static unsigned long long peers_requested;
-
-/**
- * Number of currently running peers (should be same as @c peers_requested).
- */
-static unsigned long long peers_running;
-
-/**
- * Test context (to shut down).
- */
-struct GNUNET_CADET_TEST_Context *test_ctx;
-
-/**
- * Task called to disconnect peers.
- */
-static struct GNUNET_SCHEDULER_Task *disconnect_task;
-
-/**
- * Task To perform tests
- */
-static struct GNUNET_SCHEDULER_Task *test_task;
-
-/**
- * Task runnining #send_next_msg().
- */
-static struct GNUNET_SCHEDULER_Task *send_next_msg_task;
-
-/**
- * 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 *outgoing_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;
-
-/**
- * How many messages were dropped by CADET because of full buffers?
- */
-static unsigned int msg_dropped;
-
-
-/******************************************************************************/
-
-
-/******************************************************************************/
-
-
-/**
- * Get the channel considered as the "target" or "receiver", depending on
- * the test type and size.
- *
- * @return Channel handle of the target client, either 0 (for backward tests)
- * or the last peer in the line (for other tests).
- */
-static struct GNUNET_CADET_Channel *
-get_target_channel ()
-{
- if (SPEED == test && GNUNET_YES == test_backwards)
- return outgoing_ch;
- else
- return incoming_ch;
-}
-
-
-/**
- * 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");
-}
-
-
-/**
- * Disconnect from cadet services af all peers, call shutdown.
- *
- * @param cls Closure (line number from which termination was requested).
- * @param tc Task Context.
- */
-static void
-disconnect_cadet_peers (void *cls)
-{
- long line = (long) cls;
- unsigned int i;
-
- disconnect_task = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "disconnecting cadet service of peers, called from line %ld\n",
- line);
- for (i = 0; i < 2; i++)
- {
- GNUNET_TESTBED_operation_done (t_op[i]);
- }
- if (NULL != outgoing_ch)
- {
- GNUNET_CADET_channel_destroy (outgoing_ch);
- outgoing_ch = NULL;
- }
- if (NULL != incoming_ch)
- {
- GNUNET_CADET_channel_destroy (incoming_ch);
- incoming_ch = NULL;
- }
- GNUNET_CADET_TEST_cleanup (test_ctx);
- GNUNET_SCHEDULER_shutdown ();
-}
-
-
-/**
- * Shut down peergroup, clean up.
- *
- * @param cls Closure (unused).
- * @param tc Task Context.
- */
-static void
-shutdown_task (void *cls)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n");
- if (NULL != send_next_msg_task)
- {
- GNUNET_SCHEDULER_cancel (send_next_msg_task);
- send_next_msg_task = NULL;
- }
- if (NULL != test_task)
- {
- GNUNET_SCHEDULER_cancel (test_task);
- test_task = NULL;
- }
- if (NULL != disconnect_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 (line number from which termination was requested).
- * @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, " KA sent: %u, KA received: %u\n",
- ka_sent, ka_received);
- if ((KEEPALIVE == test) && ((ka_sent < 2) || (ka_sent > ka_received + 1)))
- {
- GNUNET_break (0);
- ok--;
- }
- GNUNET_TESTBED_operation_done (stats_op);
-
- if (NULL != disconnect_task)
- GNUNET_SCHEDULER_cancel (disconnect_task);
- disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, cls);
-}
-
-
-/**
- * Process statistic values.
- *
- * @param cls closure (line number, unused)
- * @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";
- static const char *rdrops = "# messages dropped due to full buffer";
- static const char *cdrops = "# messages dropped due to slow client";
- uint32_t i;
-
- i = GNUNET_TESTBED_get_index (peer);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "STATS PEER %u - %s [%s]: %llu\n", i,
- subsystem, name, (unsigned long long) value);
- if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i)
- ka_sent = value;
- if (0 == strncmp (s_recv, name, strlen (s_recv)) && peers_requested - 1 == i)
- ka_received = value;
- if (0 == strncmp (rdrops, name, strlen (rdrops)))
- msg_dropped += value;
- if (0 == strncmp (cdrops, name, strlen (cdrops)))
- msg_dropped += value;
-
- return GNUNET_OK;
-}
-
-
-/**
- * Task to gather all statistics.
- *
- * @param cls Closure (line from which the task was scheduled).
- */
-static void
-gather_stats_and_exit (void *cls)
-{
- long l = (long) cls;
-
- disconnect_task = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "gathering statistics from line %ld\n",
- l);
- if (NULL != outgoing_ch)
- {
- GNUNET_CADET_channel_destroy (outgoing_ch);
- outgoing_ch = NULL;
- }
- stats_op = GNUNET_TESTBED_get_statistics (peers_running,
- testbed_peers,
- "cadet",
- NULL,
- &stats_iterator,
- stats_cont,
- cls);
-}
-
-
-
-/**
- * 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 (NULL != disconnect_task)
- {
- GNUNET_SCHEDULER_cancel (disconnect_task);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Aborting test from %ld\n", line);
- disconnect_task =
- GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) line);
- }
-}
-
-
-/**
- * Send a message on the channel with the appropriate size and payload.
- *
- * Update the appropriate *_sent counter.
- *
- * @param channel Channel to send the message on.
- */
-static void
-send_test_message (struct GNUNET_CADET_Channel *channel)
-{
- struct GNUNET_MQ_Envelope *env;
- struct GNUNET_MessageHeader *msg;
- uint32_t *data;
- int payload;
- int size;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending test message on channel %p\n",
- channel);
- size = size_payload;
- if (GNUNET_NO == initialized)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending INITIALIZER\n");
- size += 1000;
- payload = data_sent;
- if (SPEED_ACK == test) // FIXME unify SPEED_ACK with an initializer
- data_sent++;
- }
- else if (SPEED == test || SPEED_ACK == test)
- {
- if (get_target_channel() == channel)
- {
- payload = ack_sent;
- size += ack_sent;
- ack_sent++;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending ACK %u [%d bytes]\n",
- payload, size);
- }
- else
- {
- payload = data_sent;
- size += data_sent;
- data_sent++;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending DATA %u [%d bytes]\n",
- data_sent, size);
- }
- }
- else if (FORWARD == test)
- {
- payload = ack_sent;
- }
- else if (P2P_SIGNAL == test)
- {
- payload = data_sent;
- }
- else
- {
- GNUNET_assert (0);
- }
- env = GNUNET_MQ_msg_extra (msg, size, GNUNET_MESSAGE_TYPE_DUMMY);
-
- data = (uint32_t *) &msg[1];
- *data = htonl (payload);
- GNUNET_MQ_send (GNUNET_CADET_get_mq (channel), env);
-}
-
-/**
- * Task to request a new data transmission in a SPEED test, without waiting
- * for previous messages to be sent/arrrive.
- *
- * @param cls Closure (unused).
- */
-static void
-send_next_msg (void *cls)
-{
- struct GNUNET_CADET_Channel *channel;
-
- send_next_msg_task = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending next message: %d\n", data_sent);
-
- channel = GNUNET_YES == test_backwards ? incoming_ch : outgoing_ch;
- GNUNET_assert (NULL != channel);
- GNUNET_assert (SPEED == test);
- send_test_message (channel);
- if (data_sent < total_packets)
- {
- /* SPEED test: Send all messages as soon as possible */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Scheduling message %d\n",
- data_sent + 1);
- send_next_msg_task =
- GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_SECONDS,
- &send_next_msg,
- NULL);
- }
-}
-
-
-/**
- * Every few messages cancel the timeout task and re-schedule it again, to
- * avoid timing out when traffic keeps coming.
- *
- * @param line Code line number to log if a timeout occurs.
- */
-static void
-reschedule_timeout_task (long line)
-{
- if ((ok % 10) == 0)
- {
- if (NULL != disconnect_task)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- " reschedule timeout every 10 messages\n");
- GNUNET_SCHEDULER_cancel (disconnect_task);
- disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
- &gather_stats_and_exit,
- (void *) line);
- }
- }
-}
-
-
-/**
- * Check if payload is sane (size contains payload).
- *
- * @param cls should match #ch
- * @param message The actual message.
- * @return #GNUNET_OK to keep the channel open,
- * #GNUNET_SYSERR to close it (signal serious error).
- */
-static int
-check_data (void *cls, const struct GNUNET_MessageHeader *message)
-{
- if (sizeof (struct GNUNET_MessageHeader) >= ntohs (message->size))
- return GNUNET_SYSERR;
- return GNUNET_OK; /* all is well-formed */
-}
-
-
-/**
- * Function is called whenever a message is received.
- *
- * @param cls closure (set from GNUNET_CADET_connect(), peer number)
- * @param message the actual message
- */
-static void
-handle_data (void *cls, const struct GNUNET_MessageHeader *message)
-{
- struct CadetTestChannelWrapper *ch = cls;
- struct GNUNET_CADET_Channel *channel = ch->ch;
- uint32_t *data;
- uint32_t payload;
- int *counter;
-
- ok++;
- GNUNET_CADET_receive_done (channel);
- counter = get_target_channel () == channel ? &data_received : &ack_received;
-
- reschedule_timeout_task ((long) __LINE__);
-
- if (channel == outgoing_ch)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message.\n");
- }
- else if (channel == incoming_ch)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Leaf client got a message.\n");
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown channel %p.\n", channel);
- GNUNET_assert (0);
- }
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: (%d/%d)\n", ok, ok_goal);
- data = (uint32_t *) &message[1];
- payload = ntohl (*data);
- if (payload == *counter)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, " payload as expected: %u\n", payload);
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- " payload %u, expected: %u\n",
- payload, *counter);
- }
-
- if (GNUNET_NO == initialized)
- {
- initialized = GNUNET_YES;
- start_time = GNUNET_TIME_absolute_get ();
- if (SPEED == test)
- {
- GNUNET_assert (incoming_ch == channel);
- send_next_msg_task = GNUNET_SCHEDULER_add_now (&send_next_msg, NULL);
- return;
- }
- }
-
- (*counter)++;
- if (get_target_channel () == channel) /* Got "data" */
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received data %u\n", data_received);
- if (SPEED != test || (ok_goal - 2) == ok)
- {
- /* Send ACK */
- send_test_message (channel);
- return;
- }
- else
- {
- if (data_received < total_packets)
- return;
- }
- }
- else /* Got "ack" */
- {
- if (SPEED_ACK == test || SPEED == test)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received ack %u\n", ack_received);
- /* Send more data */
- send_test_message (channel);
- if (ack_received < total_packets && SPEED != test)
- return;
- if (ok == 2 && SPEED == test)
- return;
- show_end_data ();
- }
- if (test == P2P_SIGNAL)
- {
- GNUNET_CADET_channel_destroy (incoming_ch);
- incoming_ch = NULL;
- }
- else
- {
- GNUNET_CADET_channel_destroy (outgoing_ch);
- outgoing_ch = NULL;
- }
- }
-}
-
-
-/**
- * Method called whenever a peer connects to a port in MQ-based CADET.
- *
- * @param cls Closure from #GNUNET_CADET_open_porT (peer # as long).
- * @param channel New handle to the channel.
- * @param source Peer that started this channel.
- * @return Closure for the incoming @a channel. It's given to:
- * - The #GNUNET_CADET_DisconnectEventHandler (given to
- * #GNUNET_CADET_open_porT) when the channel dies.
- * - Each the #GNUNET_MQ_MessageCallback handlers for each message
- * received on the @a channel.
- */
-static void *
-connect_handler (void *cls, struct GNUNET_CADET_Channel *channel,
- const struct GNUNET_PeerIdentity *source)
-{
- struct CadetTestChannelWrapper *ch;
- long peer = (long) cls;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Incoming channel from %s to %ld: %p\n",
- GNUNET_i2s (source), peer, channel);
- ok++;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
- if (peer == peers_requested - 1)
- {
- if (NULL != incoming_ch)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Duplicate incoming channel for client %lu\n", (long) cls);
- GNUNET_assert (0);
- }
- incoming_ch = channel;
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Incoming channel for unexpected peer #%lu\n", (long) cls);
- GNUNET_assert (0);
- }
- if (NULL != disconnect_task)
- {
- GNUNET_SCHEDULER_cancel (disconnect_task);
- disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
- &gather_stats_and_exit,
- (void *) __LINE__);
- }
-
- /* TODO: cannot return channel as-is, in order to unify the data handlers */
- ch = GNUNET_new (struct CadetTestChannelWrapper);
- ch->ch = channel;
-
- return ch;
-}
-
-
-/**
- * Function called whenever an MQ-channel is destroyed, even if the destruction
- * was requested by #GNUNET_CADET_channel_destroy.
- * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
- *
- * It should clean up any associated state, including cancelling any pending
- * transmission on this channel.
- *
- * @param cls Channel closure (channel wrapper).
- * @param channel Connection to the other end (henceforth invalid).
- */
-static void
-disconnect_handler (void *cls, const struct GNUNET_CADET_Channel *channel)
-{
- struct CadetTestChannelWrapper *ch_w = cls;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Channel disconnected\n");
- GNUNET_assert (ch_w->ch == channel);
- if (channel == incoming_ch)
- {
- ok++;
- incoming_ch = NULL;
- }
- else if (outgoing_ch == channel
- )
- {
- if (P2P_SIGNAL == test)
- {
- ok++;
- }
- outgoing_ch = NULL;
- }
- else
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unknown channel! %p\n", channel);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
-
- if (NULL != disconnect_task)
- {
- GNUNET_SCHEDULER_cancel (disconnect_task);
- disconnect_task =
- GNUNET_SCHEDULER_add_now (&gather_stats_and_exit, (void *) __LINE__);
- }
-}
-
-
-/**
- * START THE TESTCASE ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES.
- *
- * Testcase continues when the root receives confirmation of connected peers,
- * on callback function ch.
- *
- * @param cls Closure (unused).
- */
-static void
-start_test (void *cls)
-{
- struct GNUNET_MQ_MessageHandler handlers[] = {
- GNUNET_MQ_hd_var_size (data,
- GNUNET_MESSAGE_TYPE_DUMMY,
- struct GNUNET_MessageHeader,
- NULL),
- GNUNET_MQ_handler_end ()
- };
- struct CadetTestChannelWrapper *ch;
- enum GNUNET_CADET_ChannelOption flags;
-
- test_task = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "start_test\n");
- if (NULL != disconnect_task)
- {
- GNUNET_SCHEDULER_cancel (disconnect_task);
- disconnect_task = NULL;
- }
-
- flags = GNUNET_CADET_OPTION_DEFAULT;
- if (SPEED_REL == test)
- {
- test = SPEED;
- flags |= GNUNET_CADET_OPTION_RELIABLE;
- }
-
- ch = GNUNET_new (struct CadetTestChannelWrapper);
- outgoing_ch = GNUNET_CADET_channel_creatE (h1,
- ch,
- p_id[1],
- &port,
- flags,
- NULL,
- &disconnect_handler,
- handlers);
-
- ch->ch = outgoing_ch;
-
- disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
- &gather_stats_and_exit,
- (void *) __LINE__);
- if (KEEPALIVE == test)
- return; /* Don't send any data. */
-
-
- data_received = 0;
- data_sent = 0;
- ack_received = 0;
- ack_sent = 0;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending data initializer on channel %p...\n",
- outgoing_ch);
- send_test_message (outgoing_ch);
-}
-
-
-/**
- * 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_now (&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 peers Array of peers.
- * @param cadets 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 **cadets)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n");
- ok = 0;
- test_ctx = ctx;
- peers_running = num_peers;
- GNUNET_assert (peers_running == peers_requested);
- testbed_peers = peers;
- h1 = cadets[0];
- h2 = cadets[num_peers - 1];
- disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
- &disconnect_cadet_peers,
- (void *) __LINE__);
- GNUNET_SCHEDULER_add_shutdown (&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[])
-{
- struct GNUNET_MQ_MessageHandler handlers[] = {
- GNUNET_MQ_hd_var_size (data,
- GNUNET_MESSAGE_TYPE_DUMMY,
- struct GNUNET_MessageHeader,
- NULL),
- GNUNET_MQ_handler_end ()
- };
-
- initialized = GNUNET_NO;
- static const struct GNUNET_HashCode *ports[2];
- const char *config_file;
- char port_id[] = "test port";
-
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- {'t', "time", "short_time",
- gettext_noop ("set short timeout"),
- GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &short_time},
- {'m', "messages", "NUM_MESSAGES",
- gettext_noop ("set number of messages to send"),
- GNUNET_YES, &GNUNET_GETOPT_set_uint, &total_packets},
-
- GNUNET_GETOPT_OPTION_END
- };
-
- GNUNET_log_setup ("test", "DEBUG", NULL);
-
- total_packets = TOTAL_PACKETS;
- short_time = SHORT_TIME;
- if (-1 == GNUNET_GETOPT_run (argv[0], options, argc, argv))
- {
- FPRINTF (stderr, "test failed: problem with CLI parameters\n");
- exit (1);
- }
-
- config_file = "test_cadet.conf";
- GNUNET_CRYPTO_hash (port_id, sizeof (port_id), &port);
-
- /* Find out requested size */
- if (strstr (argv[0], "_2_") != NULL)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "DIRECT CONNECTIONs\n");
- peers_requested = 2;
- }
- else if (strstr (argv[0], "_5_") != NULL)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "5 PEER LINE\n");
- peers_requested = 5;
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "SIZE UNKNOWN, USING 2\n");
- peers_requested = 2;
- }
-
- /* Find out requested test */
- if (strstr (argv[0], "_forward") != NULL)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "FORWARD\n");
- test = FORWARD;
- test_name = "unicast";
- ok_goal = 4;
- }
- else if (strstr (argv[0], "_signal") != NULL)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SIGNAL\n");
- test = P2P_SIGNAL;
- test_name = "signal";
- ok_goal = 4;
- }
- else if (strstr (argv[0], "_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], "_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] = &port;
- ports[1] = NULL;
- GNUNET_CADET_TEST_ruN ("test_cadet_small",
- config_file,
- peers_requested,
- &tmain,
- NULL, /* tmain cls */
- &connect_handler,
- NULL,
- &disconnect_handler,
- handlers,
- ports);
- if (NULL != strstr (argv[0], "_reliable"))
- msg_dropped = 0; /* dropped should be retransmitted */
-
- if (ok_goal > ok - msg_dropped)
- {
- 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_single.c b/src/cadet/test_cadet_single.c
deleted file mode 100644
index b45b0af5df..0000000000
--- a/src/cadet/test_cadet_single.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- This file is part of GNUnet.
- Copyright (C) 2011 GNUnet e.V.
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, 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 struct GNUNET_SCHEDULER_Task *abort_task;
-
-static struct GNUNET_SCHEDULER_Task *connect_task;
-
-static unsigned int repetition;
-
-static struct GNUNET_CADET_TransmitHandle *nth;
-
-static struct GNUNET_CADET_Port *port;
-
-
-/* forward declaration */
-static size_t
-do_send (void *cls, size_t size, void *buf);
-
-
-/**
- * Shutdown nicely
- */
-static void
-do_shutdown (void *cls)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "shutdown\n");
- if (NULL != port)
- {
- GNUNET_CADET_close_port (port);
- port = NULL;
- }
- if (NULL != nth)
- {
- GNUNET_CADET_notify_transmit_ready_cancel (nth);
- nth = NULL;
- }
- if (NULL != abort_task)
- {
- GNUNET_SCHEDULER_cancel (abort_task);
- abort_task = NULL;
- }
- if (NULL != connect_task)
- {
- GNUNET_SCHEDULER_cancel (connect_task);
- connect_task = NULL;
- }
- if (NULL != ch1)
- {
- GNUNET_CADET_channel_destroy (ch1);
- ch1 = NULL;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Disconnect clients\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)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ABORT\n");
- result = GNUNET_SYSERR;
- abort_task = NULL;
- GNUNET_SCHEDULER_shutdown ();
-}
-
-
-/**
- * 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++;
- if (repetition < REPETITIONS)
- {
- struct GNUNET_CADET_Channel *my_channel;
- if (0 == repetition % 2)
- my_channel = ch1;
- else
- my_channel = ch2;
- nth = 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_assert (NULL == nth);
- 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,
- const struct GNUNET_HashCode *port,
- enum GNUNET_CADET_ChannelOption options)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "received incoming channel on port %s\n",
- GNUNET_h2s (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;
-
- nth = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "incoming channel closed at peer %ld\n",
- id);
- if ( (REPETITIONS == repetition) &&
- (channel == ch2) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "everything fine! finishing!\n");
- result = GNUNET_OK;
- GNUNET_SCHEDULER_shutdown ();
- }
- if (channel == ch2)
- ch2 = NULL;
- if (channel == ch1)
- ch1 = NULL;
-}
-
-
-/**
- * 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;
-
- nth = NULL;
- if (NULL == buf)
- {
- GNUNET_break (0);
- result = GNUNET_SYSERR;
- return 0;
- }
- m->size = htons (sizeof (struct GNUNET_MessageHeader) + DATA_SIZE);
- 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).
- */
-static void
-do_connect (void *cls)
-{
- struct GNUNET_PeerIdentity id;
- size_t size = sizeof (struct GNUNET_MessageHeader) + DATA_SIZE;
-
- connect_task = NULL;
- 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, GC_u2h (1),
- GNUNET_CADET_OPTION_DEFAULT);
- nth = 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)
-{
- me = peer;
- GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
- 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 */
- &channel_end, /* inbound end hndlr */
- handlers1); /* traffic handlers */
- port = GNUNET_CADET_open_port (cadet,
- GC_u2h (1),
- &inbound_channel,
- (void *) 1L);
-
-
- if (NULL == cadet)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Couldn't connect to cadet :(\n");
- result = GNUNET_SYSERR;
- return;
- }
- connect_task
- = 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/datacache/Makefile.am b/src/datacache/Makefile.am
index 431b3179e9..670a64926e 100644
--- a/src/datacache/Makefile.am
+++ b/src/datacache/Makefile.am
@@ -53,6 +53,7 @@ libgnunet_plugin_datacache_sqlite_la_SOURCES = \
plugin_datacache_sqlite.c
libgnunet_plugin_datacache_sqlite_la_LIBADD = \
$(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/sq/libgnunetsq.la \
$(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
$(LTLIBINTL)
libgnunet_plugin_datacache_sqlite_la_LDFLAGS = \
diff --git a/src/datacache/plugin_datacache_sqlite.c b/src/datacache/plugin_datacache_sqlite.c
index 5567077d3f..5cc48b26c9 100644
--- a/src/datacache/plugin_datacache_sqlite.c
+++ b/src/datacache/plugin_datacache_sqlite.c
@@ -26,6 +26,7 @@
#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_datacache_plugin.h"
+#include "gnunet_sq_lib.h"
#include <sqlite3.h>
#define LOG(kind,...) GNUNET_log_from (kind, "datacache-sqlite", __VA_ARGS__)
@@ -60,6 +61,41 @@ struct Plugin
char *fn;
/**
+ * Prepared statement for #sqlite_plugin_put.
+ */
+ sqlite3_stmt *insert_stmt;
+
+ /**
+ * Prepared statement for #sqlite_plugin_get.
+ */
+ sqlite3_stmt *get_count_stmt;
+
+ /**
+ * Prepared statement for #sqlite_plugin_get.
+ */
+ sqlite3_stmt *get_stmt;
+
+ /**
+ * Prepared statement for #sqlite_plugin_del.
+ */
+ sqlite3_stmt *del_select_stmt;
+
+ /**
+ * Prepared statement for #sqlite_plugin_del.
+ */
+ sqlite3_stmt *del_stmt;
+
+ /**
+ * Prepared statement for #sqlite_plugin_get_random.
+ */
+ sqlite3_stmt *get_random_stmt;
+
+ /**
+ * Prepared statement for #sqlite_plugin_get_closest.
+ */
+ sqlite3_stmt *get_closest_stmt;
+
+ /**
* Number of key-value pairs in the database.
*/
unsigned int num_items;
@@ -132,60 +168,47 @@ sqlite_plugin_put (void *cls,
const struct GNUNET_PeerIdentity *path_info)
{
struct Plugin *plugin = cls;
- sqlite3_stmt *stmt;
- int64_t dval;
+ uint32_t type32 = type;
+ struct GNUNET_SQ_QueryParam params[] = {
+ GNUNET_SQ_query_param_uint32 (&type32),
+ GNUNET_SQ_query_param_absolute_time (&discard_time),
+ GNUNET_SQ_query_param_auto_from_type (key),
+ GNUNET_SQ_query_param_fixed_size (data, size),
+ GNUNET_SQ_query_param_fixed_size (path_info,
+ path_info_len * sizeof (struct GNUNET_PeerIdentity)),
+ GNUNET_SQ_query_param_end
+ };
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Processing PUT of %u bytes with key `%4s' and expiration %s\n",
+ "Processing PUT of %u bytes with key `%s' and expiration %s\n",
(unsigned int) size,
GNUNET_h2s (key),
- GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (discard_time), GNUNET_YES));
- dval = (int64_t) discard_time.abs_value_us;
- if (dval < 0)
- dval = INT64_MAX;
- if (sq_prepare
- (plugin->dbh,
- "INSERT INTO ds090 (type, expire, key, value, path) VALUES (?, ?, ?, ?, ?)",
- &stmt) != SQLITE_OK)
- {
- LOG_SQLITE (plugin->dbh,
- GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sq_prepare");
- return -1;
- }
- if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, type)) ||
- (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, dval)) ||
- (SQLITE_OK !=
- sqlite3_bind_blob (stmt, 3,
- key, sizeof (struct GNUNET_HashCode),
- SQLITE_TRANSIENT)) ||
- (SQLITE_OK != sqlite3_bind_blob (stmt, 4,
- data, size,
- SQLITE_TRANSIENT)) ||
- (SQLITE_OK != sqlite3_bind_blob (stmt, 5,
- path_info,
- path_info_len * sizeof (struct GNUNET_PeerIdentity),
- SQLITE_TRANSIENT)))
+ GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (discard_time),
+ GNUNET_YES));
+ if (GNUNET_OK !=
+ GNUNET_SQ_bind (plugin->insert_stmt,
+ params))
{
LOG_SQLITE (plugin->dbh,
GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
"sqlite3_bind_xxx");
- sqlite3_finalize (stmt);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->insert_stmt);
return -1;
}
- if (SQLITE_DONE != sqlite3_step (stmt))
+ if (SQLITE_DONE !=
+ sqlite3_step (plugin->insert_stmt))
{
LOG_SQLITE (plugin->dbh,
GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
"sqlite3_step");
- sqlite3_finalize (stmt);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->insert_stmt);
return -1;
}
plugin->num_items++;
- if (SQLITE_OK != sqlite3_finalize (stmt))
- LOG_SQLITE (plugin->dbh,
- GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sqlite3_finalize");
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->insert_stmt);
return size + OVERHEAD;
}
@@ -209,120 +232,119 @@ sqlite_plugin_get (void *cls,
void *iter_cls)
{
struct Plugin *plugin = cls;
- sqlite3_stmt *stmt;
+ uint32_t type32 = type;
struct GNUNET_TIME_Absolute now;
struct GNUNET_TIME_Absolute exp;
- unsigned int size;
- const char *dat;
+ size_t size;
+ void *dat;
unsigned int cnt;
- unsigned int off;
+ uint32_t off;
unsigned int total;
- unsigned int psize;
- char scratch[256];
- int64_t ntime;
- const struct GNUNET_PeerIdentity *path;
+ size_t psize;
+ struct GNUNET_PeerIdentity *path;
+ struct GNUNET_SQ_QueryParam params_count[] = {
+ GNUNET_SQ_query_param_auto_from_type (key),
+ GNUNET_SQ_query_param_uint32 (&type32),
+ GNUNET_SQ_query_param_absolute_time (&now),
+ GNUNET_SQ_query_param_end
+ };
+ struct GNUNET_SQ_QueryParam params_select[] = {
+ GNUNET_SQ_query_param_auto_from_type (key),
+ GNUNET_SQ_query_param_uint32 (&type32),
+ GNUNET_SQ_query_param_absolute_time (&now),
+ GNUNET_SQ_query_param_uint32 (&off),
+ GNUNET_SQ_query_param_end
+ };
+ struct GNUNET_SQ_ResultSpec rs[] = {
+ GNUNET_SQ_result_spec_variable_size (&dat,
+ &size),
+ GNUNET_SQ_result_spec_absolute_time (&exp),
+ GNUNET_SQ_result_spec_variable_size ((void **) &path,
+ &psize),
+ GNUNET_SQ_result_spec_end
+ };
now = GNUNET_TIME_absolute_get ();
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Processing GET for key `%4s'\n",
+ "Processing GET for key `%s'\n",
GNUNET_h2s (key));
- if (sq_prepare
- (plugin->dbh,
- "SELECT count(*) FROM ds090 WHERE key=? AND type=? AND expire >= ?",
- &stmt) != SQLITE_OK)
- {
- LOG_SQLITE (plugin->dbh,
- GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sq_prepare");
- return 0;
- }
- ntime = (int64_t) now.abs_value_us;
- GNUNET_assert (ntime >= 0);
- if ((SQLITE_OK !=
- sqlite3_bind_blob (stmt, 1, key, sizeof (struct GNUNET_HashCode),
- SQLITE_TRANSIENT)) ||
- (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) ||
- (SQLITE_OK != sqlite3_bind_int64 (stmt, 3, now.abs_value_us)))
+
+ if (GNUNET_OK !=
+ GNUNET_SQ_bind (plugin->get_count_stmt,
+ params_count))
{
LOG_SQLITE (plugin->dbh,
GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
"sqlite3_bind_xxx");
- sqlite3_finalize (stmt);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->get_count_stmt);
return 0;
}
-
- if (SQLITE_ROW != sqlite3_step (stmt))
+ if (SQLITE_ROW !=
+ sqlite3_step (plugin->get_count_stmt))
{
LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
"sqlite_step");
- sqlite3_finalize (stmt);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->get_count_stmt);
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "No content found when processing GET for key `%4s'\n",
+ "No content found when processing GET for key `%s'\n",
GNUNET_h2s (key));
return 0;
}
- total = sqlite3_column_int (stmt, 0);
- sqlite3_finalize (stmt);
- if ((0 == total) || (NULL == iter))
+ total = sqlite3_column_int (plugin->get_count_stmt,
+ 0);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->get_count_stmt);
+ if ( (0 == total) ||
+ (NULL == iter) )
{
if (0 == total)
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "No content found when processing GET for key `%4s'\n",
+ "No content found when processing GET for key `%s'\n",
GNUNET_h2s (key));
return total;
}
cnt = 0;
- off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total);
+ off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+ total);
while (cnt < total)
{
off = (off + 1) % total;
- GNUNET_snprintf (scratch, sizeof (scratch),
- "SELECT value,expire,path FROM ds090 WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET %u",
- off);
- if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK)
- {
- LOG_SQLITE (plugin->dbh,
- GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sq_prepare");
- return cnt;
- }
- if ((SQLITE_OK !=
- sqlite3_bind_blob (stmt, 1,
- key,
- sizeof (struct GNUNET_HashCode),
- SQLITE_TRANSIENT)) ||
- (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) ||
- (SQLITE_OK != sqlite3_bind_int64 (stmt, 3, now.abs_value_us)))
+ if (GNUNET_OK !=
+ GNUNET_SQ_bind (plugin->get_stmt,
+ params_select))
{
LOG_SQLITE (plugin->dbh,
GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
"sqlite3_bind_xxx");
- sqlite3_finalize (stmt);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->get_stmt);
return cnt;
}
- if (sqlite3_step (stmt) != SQLITE_ROW)
+ if (SQLITE_ROW !=
+ sqlite3_step (plugin->get_stmt))
break;
- size = sqlite3_column_bytes (stmt, 0);
- dat = sqlite3_column_blob (stmt, 0);
- exp.abs_value_us = sqlite3_column_int64 (stmt, 1);
- psize = sqlite3_column_bytes (stmt, 2);
+ if (GNUNET_OK !=
+ GNUNET_SQ_extract_result (plugin->get_stmt,
+ rs))
+ {
+ GNUNET_break (0);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->get_stmt);
+ break;
+ }
if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
{
GNUNET_break (0);
psize = 0;
+ path = NULL;
}
psize /= sizeof (struct GNUNET_PeerIdentity);
- if (0 != psize)
- path = sqlite3_column_blob (stmt, 2);
- else
- path = NULL;
- ntime = (int64_t) exp.abs_value_us;
- if (ntime == INT64_MAX)
- exp = GNUNET_TIME_UNIT_FOREVER_ABS;
cnt++;
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Found %u-byte result when processing GET for key `%4s'\n",
+ "Found %u-byte result when processing GET for key `%s'\n",
(unsigned int) size,
GNUNET_h2s (key));
if (GNUNET_OK != iter (iter_cls,
@@ -334,11 +356,17 @@ sqlite_plugin_get (void *cls,
psize,
path))
{
- sqlite3_finalize (stmt);
+ GNUNET_SQ_cleanup_result (rs);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->get_stmt);
break;
}
- sqlite3_finalize (stmt);
+ GNUNET_SQ_cleanup_result (rs);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->get_stmt);
}
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->get_stmt);
return cnt;
}
@@ -354,79 +382,73 @@ static int
sqlite_plugin_del (void *cls)
{
struct Plugin *plugin = cls;
- unsigned long long rowid;
- unsigned int dsize;
- sqlite3_stmt *stmt;
- sqlite3_stmt *dstmt;
+ uint64_t rowid;
+ void *data;
+ size_t dsize;
struct GNUNET_HashCode hc;
+ struct GNUNET_SQ_ResultSpec rs[] = {
+ GNUNET_SQ_result_spec_uint64 (&rowid),
+ GNUNET_SQ_result_spec_auto_from_type (&hc),
+ GNUNET_SQ_result_spec_variable_size ((void **) &data,
+ &dsize),
+ GNUNET_SQ_result_spec_end
+ };
+ struct GNUNET_SQ_QueryParam params[] = {
+ GNUNET_SQ_query_param_uint64 (&rowid),
+ GNUNET_SQ_query_param_end
+ };
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Processing DEL\n");
- stmt = NULL;
- dstmt = NULL;
- if (SQLITE_OK !=
- sq_prepare (plugin->dbh,
- "SELECT _ROWID_,key,value FROM ds090 ORDER BY expire ASC LIMIT 1",
- &stmt))
- {
- LOG_SQLITE (plugin->dbh,
- GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sq_prepare");
- if (stmt != NULL)
- (void) sqlite3_finalize (stmt);
- return GNUNET_SYSERR;
- }
- if (SQLITE_ROW != sqlite3_step (stmt))
+ if (SQLITE_ROW !=
+ sqlite3_step (plugin->del_select_stmt))
{
LOG_SQLITE (plugin->dbh,
GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
"sqlite3_step");
- (void) sqlite3_finalize (stmt);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->del_select_stmt);
return GNUNET_SYSERR;
}
- rowid = sqlite3_column_int64 (stmt, 0);
- GNUNET_assert (sqlite3_column_bytes (stmt, 1) == sizeof (struct GNUNET_HashCode));
- GNUNET_memcpy (&hc, sqlite3_column_blob (stmt, 1), sizeof (struct GNUNET_HashCode));
- dsize = sqlite3_column_bytes (stmt, 2);
- if (SQLITE_OK != sqlite3_finalize (stmt))
- LOG_SQLITE (plugin->dbh,
- GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sqlite3_step");
- if (SQLITE_OK !=
- sq_prepare (plugin->dbh,
- "DELETE FROM ds090 WHERE _ROWID_=?", &dstmt))
+ if (GNUNET_OK !=
+ GNUNET_SQ_extract_result (plugin->del_select_stmt,
+ rs))
{
- LOG_SQLITE (plugin->dbh,
- GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sq_prepare");
- if (stmt != NULL)
- (void) sqlite3_finalize (stmt);
+ GNUNET_break (0);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->del_select_stmt);
return GNUNET_SYSERR;
}
- if (SQLITE_OK != sqlite3_bind_int64 (dstmt, 1, rowid))
+ GNUNET_SQ_cleanup_result (rs);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->del_select_stmt);
+ if (GNUNET_OK !=
+ GNUNET_SQ_bind (plugin->del_stmt,
+ params))
{
LOG_SQLITE (plugin->dbh,
GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
"sqlite3_bind");
- (void) sqlite3_finalize (dstmt);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->del_stmt);
return GNUNET_SYSERR;
}
- if (SQLITE_DONE != sqlite3_step (dstmt))
+ if (SQLITE_DONE !=
+ sqlite3_step (plugin->del_stmt))
{
LOG_SQLITE (plugin->dbh,
GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
"sqlite3_step");
- (void) sqlite3_finalize (dstmt);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->del_stmt);
return GNUNET_SYSERR;
}
plugin->num_items--;
plugin->env->delete_notify (plugin->env->cls,
&hc,
dsize + OVERHEAD);
- if (SQLITE_OK != sqlite3_finalize (dstmt))
- LOG_SQLITE (plugin->dbh,
- GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sqlite3_finalize");
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->del_stmt);
return GNUNET_OK;
}
@@ -445,17 +467,28 @@ sqlite_plugin_get_random (void *cls,
void *iter_cls)
{
struct Plugin *plugin = cls;
- sqlite3_stmt *stmt;
struct GNUNET_TIME_Absolute exp;
- unsigned int size;
- const char *dat;
- unsigned int off;
- unsigned int psize;
- unsigned int type;
- char scratch[256];
- int64_t ntime;
- const struct GNUNET_PeerIdentity *path;
- const struct GNUNET_HashCode *key;
+ size_t size;
+ void *dat;
+ uint32_t off;
+ size_t psize;
+ uint32_t type;
+ struct GNUNET_PeerIdentity *path;
+ struct GNUNET_HashCode key;
+ struct GNUNET_SQ_QueryParam params[] = {
+ GNUNET_SQ_query_param_uint32 (&off),
+ GNUNET_SQ_query_param_end
+ };
+ struct GNUNET_SQ_ResultSpec rs[] = {
+ GNUNET_SQ_result_spec_variable_size (&dat,
+ &size),
+ GNUNET_SQ_result_spec_absolute_time (&exp),
+ GNUNET_SQ_result_spec_variable_size ((void **) &path,
+ &psize),
+ GNUNET_SQ_result_spec_auto_from_type (&key),
+ GNUNET_SQ_result_spec_uint32 (&type),
+ GNUNET_SQ_result_spec_end
+ };
if (0 == plugin->num_items)
return 0;
@@ -463,60 +496,51 @@ sqlite_plugin_get_random (void *cls,
return 1;
off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
plugin->num_items);
- GNUNET_snprintf (scratch,
- sizeof (scratch),
- "SELECT value,expire,path,key,type FROM ds090 ORDER BY key LIMIT 1 OFFSET %u",
- off);
- if (SQLITE_OK !=
- sq_prepare (plugin->dbh, scratch, &stmt))
+ if (GNUNET_OK !=
+ GNUNET_SQ_bind (plugin->get_random_stmt,
+ params))
{
- LOG_SQLITE (plugin->dbh,
- GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sq_prepare");
return 0;
}
- if (SQLITE_ROW != sqlite3_step (stmt))
+ if (SQLITE_ROW !=
+ sqlite3_step (plugin->get_random_stmt))
+ {
+ GNUNET_break (0);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->get_random_stmt);
+ return 0;
+ }
+ if (GNUNET_OK !=
+ GNUNET_SQ_extract_result (plugin->get_random_stmt,
+ rs))
{
GNUNET_break (0);
- sqlite3_finalize (stmt);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->get_random_stmt);
return 0;
}
- size = sqlite3_column_bytes (stmt, 0);
- dat = sqlite3_column_blob (stmt, 0);
- exp.abs_value_us = sqlite3_column_int64 (stmt, 1);
- psize = sqlite3_column_bytes (stmt, 2);
if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
{
GNUNET_break (0);
psize = 0;
+ path = NULL;
}
psize /= sizeof (struct GNUNET_PeerIdentity);
- if (0 != psize)
- path = sqlite3_column_blob (stmt, 2);
- else
- path = NULL;
-
- GNUNET_assert (sizeof (struct GNUNET_HashCode) ==
- sqlite3_column_bytes (stmt, 3));
- key = sqlite3_column_blob (stmt, 3);
- type = sqlite3_column_int (stmt, 4);
-
- ntime = (int64_t) exp.abs_value_us;
- if (ntime == INT64_MAX)
- exp = GNUNET_TIME_UNIT_FOREVER_ABS;
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Found %u-byte result with key %s when processing GET-RANDOM\n",
(unsigned int) size,
- GNUNET_h2s (key));
+ GNUNET_h2s (&key));
(void) iter (iter_cls,
- key,
+ &key,
size,
dat,
- type,
+ (enum GNUNET_BLOCK_Type) type,
exp,
psize,
path);
- sqlite3_finalize (stmt);
+ GNUNET_SQ_cleanup_result (rs);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->get_random_stmt);
return 1;
}
@@ -542,83 +566,73 @@ sqlite_plugin_get_closest (void *cls,
void *iter_cls)
{
struct Plugin *plugin = cls;
- sqlite3_stmt *stmt;
+ uint32_t num_results32 = num_results;
struct GNUNET_TIME_Absolute now;
struct GNUNET_TIME_Absolute exp;
- unsigned int size;
- const char *dat;
+ size_t size;
+ void *dat;
unsigned int cnt;
- unsigned int psize;
- unsigned int type;
- int64_t ntime;
- const struct GNUNET_PeerIdentity *path;
+ size_t psize;
+ uint32_t type;
+ struct GNUNET_HashCode hc;
+ struct GNUNET_PeerIdentity *path;
+ struct GNUNET_SQ_QueryParam params[] = {
+ GNUNET_SQ_query_param_auto_from_type (key),
+ GNUNET_SQ_query_param_absolute_time (&now),
+ GNUNET_SQ_query_param_uint32 (&num_results32),
+ GNUNET_SQ_query_param_end
+ };
+ struct GNUNET_SQ_ResultSpec rs[] = {
+ GNUNET_SQ_result_spec_variable_size (&dat,
+ &size),
+ GNUNET_SQ_result_spec_absolute_time (&exp),
+ GNUNET_SQ_result_spec_variable_size ((void **) &path,
+ &psize),
+ GNUNET_SQ_result_spec_uint32 (&type),
+ GNUNET_SQ_result_spec_auto_from_type (&hc),
+ GNUNET_SQ_result_spec_end
+ };
now = GNUNET_TIME_absolute_get ();
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Processing GET_CLOSEST for key `%4s'\n",
+ "Processing GET_CLOSEST for key `%s'\n",
GNUNET_h2s (key));
- if (SQLITE_OK !=
- sq_prepare (plugin->dbh,
- "SELECT value,expire,path,type,key FROM ds090 WHERE key>=? AND expire >= ? ORDER BY KEY ASC LIMIT ?",
- &stmt))
- {
- LOG_SQLITE (plugin->dbh,
- GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sq_prepare");
- return 0;
- }
- ntime = (int64_t) now.abs_value_us;
- GNUNET_assert (ntime >= 0);
- if ((SQLITE_OK !=
- sqlite3_bind_blob (stmt,
- 1,
- key,
- sizeof (struct GNUNET_HashCode),
- SQLITE_TRANSIENT)) ||
- (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, now.abs_value_us)) ||
- (SQLITE_OK != sqlite3_bind_int (stmt, 3, num_results)) )
+ if (GNUNET_OK !=
+ GNUNET_SQ_bind (plugin->get_closest_stmt,
+ params))
{
LOG_SQLITE (plugin->dbh,
GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
"sqlite3_bind_xxx");
- sqlite3_finalize (stmt);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->get_closest_stmt);
return 0;
}
cnt = 0;
- while (SQLITE_ROW == sqlite3_step (stmt))
+ while (SQLITE_ROW ==
+ sqlite3_step (plugin->get_closest_stmt))
{
- if (sizeof (struct GNUNET_HashCode) !=
- sqlite3_column_bytes (stmt, 4))
+ if (GNUNET_OK !=
+ GNUNET_SQ_extract_result (plugin->get_closest_stmt,
+ rs))
{
GNUNET_break (0);
break;
}
- size = sqlite3_column_bytes (stmt, 0);
- dat = sqlite3_column_blob (stmt, 0);
- exp.abs_value_us = sqlite3_column_int64 (stmt, 1);
- psize = sqlite3_column_bytes (stmt, 2);
- type = sqlite3_column_int (stmt, 3);
- key = sqlite3_column_blob (stmt, 4);
if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
{
GNUNET_break (0);
psize = 0;
+ path = NULL;
}
psize /= sizeof (struct GNUNET_PeerIdentity);
- if (0 != psize)
- path = sqlite3_column_blob (stmt, 2);
- else
- path = NULL;
- ntime = (int64_t) exp.abs_value_us;
- if (ntime == INT64_MAX)
- exp = GNUNET_TIME_UNIT_FOREVER_ABS;
cnt++;
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Found %u-byte result at %s when processing GET_CLOSE\n",
(unsigned int) size,
- GNUNET_h2s (key));
+ GNUNET_h2s (&hc));
if (GNUNET_OK != iter (iter_cls,
- key,
+ &hc,
size,
dat,
type,
@@ -626,11 +640,13 @@ sqlite_plugin_get_closest (void *cls,
psize,
path))
{
- sqlite3_finalize (stmt);
+ GNUNET_SQ_cleanup_result (rs);
break;
}
+ GNUNET_SQ_cleanup_result (rs);
}
- sqlite3_finalize (stmt);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->get_closest_stmt);
return cnt;
}
@@ -703,6 +719,50 @@ libgnunet_plugin_datacache_sqlite_init (void *cls)
plugin->env = env;
plugin->dbh = dbh;
plugin->fn = fn_utf8;
+
+ if ( (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "INSERT INTO ds090 (type, expire, key, value, path) "
+ "VALUES (?, ?, ?, ?, ?)",
+ &plugin->insert_stmt)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT count(*) FROM ds090 "
+ "WHERE key=? AND type=? AND expire >= ?",
+ &plugin->get_count_stmt)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT value,expire,path FROM ds090 "
+ "WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET ?",
+ &plugin->get_stmt)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT _ROWID_,key,value FROM ds090 ORDER BY expire ASC LIMIT 1",
+ &plugin->del_select_stmt)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "DELETE FROM ds090 WHERE _ROWID_=?",
+ &plugin->del_stmt)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT value,expire,path,key,type FROM ds090 "
+ "ORDER BY key LIMIT 1 OFFSET ?",
+ &plugin->get_random_stmt)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT value,expire,path,type,key FROM ds090 "
+ "WHERE key>=? AND expire >= ? ORDER BY KEY ASC LIMIT ?",
+ &plugin->get_closest_stmt))
+ )
+ {
+ LOG_SQLITE (plugin->dbh,
+ GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ "sq_prepare");
+ (void) sqlite3_close (plugin->dbh);
+ GNUNET_free (plugin);
+ return NULL;
+ }
+
api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions);
api->cls = plugin;
api->get = &sqlite_plugin_get;
@@ -741,6 +801,13 @@ libgnunet_plugin_datacache_sqlite_done (void *cls)
plugin->fn);
GNUNET_free_non_null (plugin->fn);
#endif
+ sqlite3_finalize (plugin->insert_stmt);
+ sqlite3_finalize (plugin->get_count_stmt);
+ sqlite3_finalize (plugin->get_stmt);
+ sqlite3_finalize (plugin->del_select_stmt);
+ sqlite3_finalize (plugin->del_stmt);
+ sqlite3_finalize (plugin->get_random_stmt);
+ sqlite3_finalize (plugin->get_closest_stmt);
result = sqlite3_close (plugin->dbh);
#if SQLITE_VERSION_NUMBER >= 3007000
if (SQLITE_BUSY == result)
diff --git a/src/datastore/plugin_datastore_sqlite.c b/src/datastore/plugin_datastore_sqlite.c
index 9c67d242eb..491f73ed5e 100644
--- a/src/datastore/plugin_datastore_sqlite.c
+++ b/src/datastore/plugin_datastore_sqlite.c
@@ -128,6 +128,46 @@ struct Plugin
sqlite3_stmt *insertContent;
/**
+ * Precompiled SQL for selection
+ */
+ sqlite3_stmt *count_key;
+
+ /**
+ * Precompiled SQL for selection
+ */
+ sqlite3_stmt *count_key_vhash;
+
+ /**
+ * Precompiled SQL for selection
+ */
+ sqlite3_stmt *count_key_type;
+
+ /**
+ * Precompiled SQL for selection
+ */
+ sqlite3_stmt *count_key_vhash_type;
+
+ /**
+ * Precompiled SQL for selection
+ */
+ sqlite3_stmt *get_key;
+
+ /**
+ * Precompiled SQL for selection
+ */
+ sqlite3_stmt *get_key_vhash;
+
+ /**
+ * Precompiled SQL for selection
+ */
+ sqlite3_stmt *get_key_type;
+
+ /**
+ * Precompiled SQL for selection
+ */
+ sqlite3_stmt *get_key_vhash_type;
+
+ /**
* Should the database be dropped on shutdown?
*/
int drop_on_shutdown;
@@ -151,11 +191,17 @@ sq_prepare (sqlite3 *dbh,
char *dummy;
int result;
- result =
- sqlite3_prepare_v2 (dbh, zSql, strlen (zSql), ppStmt,
- (const char **) &dummy);
- GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
- "Prepared `%s' / %p: %d\n", zSql, *ppStmt, result);
+ result = sqlite3_prepare_v2 (dbh,
+ zSql,
+ strlen (zSql),
+ ppStmt,
+ (const char **) &dummy);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+ "sqlite",
+ "Prepared `%s' / %p: %d\n",
+ zSql,
+ *ppStmt,
+ result);
return result;
}
@@ -311,80 +357,134 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
* we do math or inequality tests, so we can't handle the entire range of uint32_t.
* This will also cause problems for expiration times after 294247-01-10-04:00:54 UTC.
*/
- if ((sqlite3_step (stmt) == SQLITE_DONE) &&
- (sqlite3_exec
- (plugin->dbh,
- "CREATE TABLE gn090 (" " repl INT4 NOT NULL DEFAULT 0,"
- " type INT4 NOT NULL DEFAULT 0," " prio INT4 NOT NULL DEFAULT 0,"
- " anonLevel INT4 NOT NULL DEFAULT 0,"
- " expire INT8 NOT NULL DEFAULT 0," " rvalue INT8 NOT NULL,"
- " hash TEXT NOT NULL DEFAULT ''," " vhash TEXT NOT NULL DEFAULT '',"
- " value BLOB NOT NULL DEFAULT '')", NULL, NULL, NULL) != SQLITE_OK))
+ if ( (SQLITE_DONE ==
+ sqlite3_step (stmt)) &&
+ (SQLITE_OK !=
+ sqlite3_exec (plugin->dbh,
+ "CREATE TABLE gn090 (" " repl INT4 NOT NULL DEFAULT 0,"
+ " type INT4 NOT NULL DEFAULT 0," " prio INT4 NOT NULL DEFAULT 0,"
+ " anonLevel INT4 NOT NULL DEFAULT 0,"
+ " expire INT8 NOT NULL DEFAULT 0," " rvalue INT8 NOT NULL,"
+ " hash TEXT NOT NULL DEFAULT ''," " vhash TEXT NOT NULL DEFAULT '',"
+ " value BLOB NOT NULL DEFAULT '')",
+ NULL,
+ NULL,
+ NULL)) )
{
- LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec");
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR,
+ "sqlite3_exec");
sqlite3_finalize (stmt);
return GNUNET_SYSERR;
}
sqlite3_finalize (stmt);
create_indices (plugin->dbh);
- if ((sq_prepare
- (plugin->dbh,
- "UPDATE gn090 "
- "SET prio = prio + ?, expire = MAX(expire,?) WHERE _ROWID_ = ?",
- &plugin->updPrio) != SQLITE_OK) ||
- (sq_prepare
- (plugin->dbh,
- "UPDATE gn090 " "SET repl = MAX (0, repl - 1) WHERE _ROWID_ = ?",
- &plugin->updRepl) != SQLITE_OK) ||
- (sq_prepare
- (plugin->dbh,
- "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 "
+ if ( (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "UPDATE gn090 "
+ "SET prio = prio + ?, expire = MAX(expire,?) WHERE _ROWID_ = ?",
+ &plugin->updPrio)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "UPDATE gn090 " "SET repl = MAX (0, repl - 1) WHERE _ROWID_ = ?",
+ &plugin->updRepl)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 "
#if SQLITE_VERSION_NUMBER >= 3007000
- "INDEXED BY idx_repl_rvalue "
+ "INDEXED BY idx_repl_rvalue "
#endif
- "WHERE repl=?2 AND " " (rvalue>=?1 OR "
- " NOT EXISTS (SELECT 1 FROM gn090 "
+ "WHERE repl=?2 AND " " (rvalue>=?1 OR "
+ " NOT EXISTS (SELECT 1 FROM gn090 "
#if SQLITE_VERSION_NUMBER >= 3007000
- "INDEXED BY idx_repl_rvalue "
+ "INDEXED BY idx_repl_rvalue "
#endif
- "WHERE repl=?2 AND rvalue>=?1 LIMIT 1) ) "
- "ORDER BY rvalue ASC LIMIT 1", &plugin->selRepl) != SQLITE_OK) ||
- (sq_prepare (plugin->dbh, "SELECT MAX(repl) FROM gn090"
+ "WHERE repl=?2 AND rvalue>=?1 LIMIT 1) ) "
+ "ORDER BY rvalue ASC LIMIT 1",
+ &plugin->selRepl)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT MAX(repl) FROM gn090"
#if SQLITE_VERSION_NUMBER >= 3007000
- " INDEXED BY idx_repl_rvalue"
+ " INDEXED BY idx_repl_rvalue"
#endif
- "", &plugin->maxRepl) != SQLITE_OK) ||
- (sq_prepare
- (plugin->dbh,
- "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 "
+ "",
+ &plugin->maxRepl)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 "
#if SQLITE_VERSION_NUMBER >= 3007000
- "INDEXED BY idx_expire "
+ "INDEXED BY idx_expire "
#endif
- "WHERE NOT EXISTS (SELECT 1 FROM gn090 WHERE expire < ?1 LIMIT 1) OR (expire < ?1) "
- "ORDER BY expire ASC LIMIT 1", &plugin->selExpi) != SQLITE_OK) ||
- (sq_prepare
- (plugin->dbh,
- "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 "
+ "WHERE NOT EXISTS (SELECT 1 FROM gn090 WHERE expire < ?1 LIMIT 1) OR (expire < ?1) "
+ "ORDER BY expire ASC LIMIT 1",
+ &plugin->selExpi)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 "
#if SQLITE_VERSION_NUMBER >= 3007000
- "INDEXED BY idx_anon_type_hash "
+ "INDEXED BY idx_anon_type_hash "
#endif
- "WHERE (anonLevel = 0 AND type=?1) "
- "ORDER BY hash DESC LIMIT 1 OFFSET ?2",
- &plugin->selZeroAnon) != SQLITE_OK) ||
- (sq_prepare
- (plugin->dbh,
- "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) "
- "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
- &plugin->insertContent) != SQLITE_OK) ||
- (sq_prepare
- (plugin->dbh, "DELETE FROM gn090 WHERE _ROWID_ = ?",
- &plugin->delRow) != SQLITE_OK))
+ "WHERE (anonLevel = 0 AND type=?1) "
+ "ORDER BY hash DESC LIMIT 1 OFFSET ?2",
+ &plugin->selZeroAnon)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
+ &plugin->insertContent)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT count(*) FROM gn090 WHERE hash=?",
+ &plugin->count_key)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT count(*) FROM gn090 WHERE hash=? AND vhash=?",
+ &plugin->count_key_vhash)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT count(*) FROM gn090 WHERE hash=? AND type=?",
+ &plugin->count_key_type)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT count(*) FROM gn090 WHERE hash=? AND vhash=? AND type=?",
+ &plugin->count_key_vhash_type)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ FROM gn090 "
+ "WHERE hash=?"
+ "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?",
+ &plugin->get_key)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ FROM gn090 "
+ "WHERE hash=? AND vhash=?"
+ "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?",
+ &plugin->get_key_vhash)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ FROM gn090 "
+ "WHERE hash=? AND type=?"
+ "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?",
+ &plugin->get_key_type)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ FROM gn090 "
+ "WHERE hash=? AND vhash=? AND type=?"
+ "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?",
+ &plugin->get_key_vhash_type)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "DELETE FROM gn090 WHERE _ROWID_ = ?",
+ &plugin->delRow))
+ )
{
- LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "precompiling");
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR,
+ "precompiling");
return GNUNET_SYSERR;
}
-
return GNUNET_OK;
}
@@ -399,51 +499,74 @@ static void
database_shutdown (struct Plugin *plugin)
{
int result;
-
#if SQLITE_VERSION_NUMBER >= 3007000
sqlite3_stmt *stmt;
#endif
- if (plugin->delRow != NULL)
+ if (NULL != plugin->delRow)
sqlite3_finalize (plugin->delRow);
- if (plugin->updPrio != NULL)
+ if (NULL != plugin->updPrio)
sqlite3_finalize (plugin->updPrio);
- if (plugin->updRepl != NULL)
+ if (NULL != plugin->updRepl)
sqlite3_finalize (plugin->updRepl);
- if (plugin->selRepl != NULL)
+ if (NULL != plugin->selRepl)
sqlite3_finalize (plugin->selRepl);
- if (plugin->maxRepl != NULL)
+ if (NULL != plugin->maxRepl)
sqlite3_finalize (plugin->maxRepl);
- if (plugin->selExpi != NULL)
+ if (NULL != plugin->selExpi)
sqlite3_finalize (plugin->selExpi);
- if (plugin->selZeroAnon != NULL)
+ if (NULL != plugin->selZeroAnon)
sqlite3_finalize (plugin->selZeroAnon);
- if (plugin->insertContent != NULL)
+ if (NULL != plugin->insertContent)
sqlite3_finalize (plugin->insertContent);
+ if (NULL != plugin->count_key)
+ sqlite3_finalize (plugin->count_key);
+ if (NULL != plugin->count_key_vhash)
+ sqlite3_finalize (plugin->count_key_vhash);
+ if (NULL != plugin->count_key_type)
+ sqlite3_finalize (plugin->count_key_type);
+ if (NULL != plugin->count_key_vhash_type)
+ sqlite3_finalize (plugin->count_key_vhash_type);
+ if (NULL != plugin->count_key)
+ sqlite3_finalize (plugin->get_key);
+ if (NULL != plugin->count_key_vhash)
+ sqlite3_finalize (plugin->get_key_vhash);
+ if (NULL != plugin->count_key_type)
+ sqlite3_finalize (plugin->get_key_type);
+ if (NULL != plugin->count_key_vhash_type)
+ sqlite3_finalize (plugin->get_key_vhash_type);
result = sqlite3_close (plugin->dbh);
#if SQLITE_VERSION_NUMBER >= 3007000
if (result == SQLITE_BUSY)
{
- GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite",
- _
- ("Tried to close sqlite without finalizing all prepared statements.\n"));
- stmt = sqlite3_next_stmt (plugin->dbh, NULL);
- while (stmt != NULL)
+ GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
+ "sqlite",
+ _("Tried to close sqlite without finalizing all prepared statements.\n"));
+ stmt = sqlite3_next_stmt (plugin->dbh,
+ NULL);
+ while (NULL != stmt)
{
- GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
- "Closing statement %p\n", stmt);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+ "sqlite",
+ "Closing statement %p\n",
+ stmt);
result = sqlite3_finalize (stmt);
if (result != SQLITE_OK)
- GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite",
- "Failed to close statement %p: %d\n", stmt, result);
- stmt = sqlite3_next_stmt (plugin->dbh, NULL);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
+ "sqlite",
+ "Failed to close statement %p: %d\n",
+ stmt,
+ result);
+ stmt = sqlite3_next_stmt (plugin->dbh,
+ NULL);
}
result = sqlite3_close (plugin->dbh);
}
#endif
if (SQLITE_OK != result)
- LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close");
-
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR,
+ "sqlite3_close");
GNUNET_free_non_null (plugin->fn);
}
@@ -472,15 +595,12 @@ delete_by_rowid (struct Plugin *plugin,
{
LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
"sqlite3_step");
- if (SQLITE_OK != sqlite3_reset (plugin->delRow))
- LOG_SQLITE (plugin,
- GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sqlite3_reset");
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->delRow);
return GNUNET_SYSERR;
}
- if (SQLITE_OK != sqlite3_reset (plugin->delRow))
- LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sqlite3_reset");
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->delRow);
return GNUNET_OK;
}
@@ -515,9 +635,10 @@ sqlite_plugin_put (void *cls,
{
uint64_t rvalue;
struct GNUNET_HashCode vhash;
+ uint32_t type32 = (uint32_t) type;
struct GNUNET_SQ_QueryParam params[] = {
GNUNET_SQ_query_param_uint32 (&replication),
- GNUNET_SQ_query_param_uint32 (&type),
+ GNUNET_SQ_query_param_uint32 (&type32),
GNUNET_SQ_query_param_uint32 (&priority),
GNUNET_SQ_query_param_uint32 (&anonymity),
GNUNET_SQ_query_param_absolute_time (&expiration),
@@ -578,19 +699,16 @@ sqlite_plugin_put (void *cls,
default:
LOG_SQLITE_MSG (plugin, &msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
"sqlite3_step");
- if (SQLITE_OK != sqlite3_reset (stmt))
- LOG_SQLITE (plugin,
- GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sqlite3_reset");
+ GNUNET_SQ_reset (plugin->dbh,
+ stmt);
database_shutdown (plugin);
database_setup (plugin->env->cfg, plugin);
cont (cont_cls, key, size, GNUNET_SYSERR, msg);
GNUNET_free_non_null(msg);
return;
}
- if (SQLITE_OK != sqlite3_reset (stmt))
- LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sqlite3_reset");
+ GNUNET_SQ_reset (plugin->dbh,
+ stmt);
cont (cont_cls, key, size, ret, msg);
GNUNET_free_non_null(msg);
}
@@ -644,9 +762,8 @@ sqlite_plugin_update (void *cls,
return;
}
n = sqlite3_step (plugin->updPrio);
- if (SQLITE_OK != sqlite3_reset (plugin->updPrio))
- LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sqlite3_reset");
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->updPrio);
switch (n)
{
case SQLITE_DONE:
@@ -687,75 +804,84 @@ execute_get (struct Plugin *plugin,
{
int n;
struct GNUNET_TIME_Absolute expiration;
- unsigned long long rowid;
- unsigned int size;
+ uint32_t type;
+ uint32_t priority;
+ uint32_t anonymity;
+ uint64_t rowid;
+ void *value;
+ size_t value_size;
+ struct GNUNET_HashCode key;
int ret;
+ struct GNUNET_SQ_ResultSpec rs[] = {
+ GNUNET_SQ_result_spec_uint32 (&type),
+ GNUNET_SQ_result_spec_uint32 (&priority),
+ GNUNET_SQ_result_spec_uint32 (&anonymity),
+ GNUNET_SQ_result_spec_absolute_time (&expiration),
+ GNUNET_SQ_result_spec_auto_from_type (&key),
+ GNUNET_SQ_result_spec_variable_size (&value,
+ &value_size),
+ GNUNET_SQ_result_spec_uint64 (&rowid),
+ GNUNET_SQ_result_spec_end
+ };
n = sqlite3_step (stmt);
switch (n)
{
case SQLITE_ROW:
- size = sqlite3_column_bytes (stmt, 5);
- rowid = sqlite3_column_int64 (stmt, 6);
- if (sqlite3_column_bytes (stmt, 4) != sizeof (struct GNUNET_HashCode))
+ if (GNUNET_OK !=
+ GNUNET_SQ_extract_result (stmt,
+ rs))
{
- GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite",
- _("Invalid data in database. Trying to fix (by deletion).\n"));
- if (SQLITE_OK != sqlite3_reset (stmt))
- LOG_SQLITE (plugin,
- GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sqlite3_reset");
- if ( (GNUNET_OK == delete_by_rowid (plugin, rowid)) &&
- (NULL != plugin->env->duc) )
- plugin->env->duc (plugin->env->cls,
- -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
+ GNUNET_break (0);
break;
}
- expiration.abs_value_us = sqlite3_column_int64 (stmt, 3);
- GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+ "sqlite",
"Found reply in database with expiration %s\n",
GNUNET_STRINGS_absolute_time_to_string (expiration));
- ret = proc (proc_cls, sqlite3_column_blob (stmt, 4) /* key */ ,
- size, sqlite3_column_blob (stmt, 5) /* data */ ,
- sqlite3_column_int (stmt, 0) /* type */ ,
- sqlite3_column_int (stmt, 1) /* priority */ ,
- sqlite3_column_int (stmt, 2) /* anonymity */ ,
- expiration, rowid);
- if (SQLITE_OK != sqlite3_reset (stmt))
- LOG_SQLITE (plugin,
- GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sqlite3_reset");
+ ret = proc (proc_cls,
+ &key,
+ value_size,
+ value,
+ type,
+ priority,
+ anonymity,
+ expiration,
+ rowid);
+ GNUNET_SQ_cleanup_result (rs);
+ GNUNET_SQ_reset (plugin->dbh,
+ stmt);
if ( (GNUNET_NO == ret) &&
- (GNUNET_OK == delete_by_rowid (plugin, rowid)) &&
+ (GNUNET_OK == delete_by_rowid (plugin,
+ rowid)) &&
(NULL != plugin->env->duc) )
plugin->env->duc (plugin->env->cls,
- -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
+ -(value_size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
return;
case SQLITE_DONE:
/* database must be empty */
- if (SQLITE_OK != sqlite3_reset (stmt))
- LOG_SQLITE (plugin,
- GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sqlite3_reset");
break;
case SQLITE_BUSY:
case SQLITE_ERROR:
case SQLITE_MISUSE:
default:
- LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
"sqlite3_step");
- if (SQLITE_OK != sqlite3_reset (stmt))
+ if (SQLITE_OK !=
+ sqlite3_reset (stmt))
LOG_SQLITE (plugin,
GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
"sqlite3_reset");
GNUNET_break (0);
+ proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
database_shutdown (plugin);
- database_setup (plugin->env->cfg, plugin);
- break;
+ database_setup (plugin->env->cfg,
+ plugin);
+ return;
}
- if (SQLITE_OK != sqlite3_reset (stmt))
- LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sqlite3_reset");
+ GNUNET_SQ_reset (plugin->dbh,
+ stmt);
proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
}
@@ -774,7 +900,8 @@ execute_get (struct Plugin *plugin,
* @param proc_cls closure for @a proc
*/
static void
-sqlite_plugin_get_zero_anonymity (void *cls, uint64_t offset,
+sqlite_plugin_get_zero_anonymity (void *cls,
+ uint64_t offset,
enum GNUNET_BLOCK_Type type,
PluginDatumProcessor proc,
void *proc_cls)
@@ -826,97 +953,133 @@ sqlite_plugin_get_key (void *cls,
void *proc_cls)
{
struct Plugin *plugin = cls;
+ uint32_t type32 = (uint32_t) type;
int ret;
int total;
- int limit_off;
- unsigned int sqoff;
- sqlite3_stmt *stmt;
- char scratch[256];
-
- GNUNET_assert (proc != NULL);
- GNUNET_assert (key != NULL);
- GNUNET_snprintf (scratch, sizeof (scratch),
- "SELECT count(*) FROM gn090 WHERE hash=?%s%s",
- vhash == NULL ? "" : " AND vhash=?",
- type == 0 ? "" : " AND type=?");
- if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK)
+ uint32_t limit_off;
+ struct GNUNET_SQ_QueryParam count_params_key[] = {
+ GNUNET_SQ_query_param_auto_from_type (key),
+ GNUNET_SQ_query_param_end
+ };
+ struct GNUNET_SQ_QueryParam count_params_key_vhash[] = {
+ GNUNET_SQ_query_param_auto_from_type (key),
+ GNUNET_SQ_query_param_auto_from_type (vhash),
+ GNUNET_SQ_query_param_end
+ };
+ struct GNUNET_SQ_QueryParam count_params_key_type[] = {
+ GNUNET_SQ_query_param_auto_from_type (key),
+ GNUNET_SQ_query_param_uint32 (&type32),
+ GNUNET_SQ_query_param_end
+ };
+ struct GNUNET_SQ_QueryParam count_params_key_vhash_type[] = {
+ GNUNET_SQ_query_param_auto_from_type (key),
+ GNUNET_SQ_query_param_auto_from_type (vhash),
+ GNUNET_SQ_query_param_uint32 (&type32),
+ GNUNET_SQ_query_param_end
+ };
+ struct GNUNET_SQ_QueryParam get_params_key[] = {
+ GNUNET_SQ_query_param_auto_from_type (key),
+ GNUNET_SQ_query_param_uint32 (&limit_off),
+ GNUNET_SQ_query_param_end
+ };
+ struct GNUNET_SQ_QueryParam get_params_key_vhash[] = {
+ GNUNET_SQ_query_param_auto_from_type (key),
+ GNUNET_SQ_query_param_auto_from_type (vhash),
+ GNUNET_SQ_query_param_uint32 (&limit_off),
+ GNUNET_SQ_query_param_end
+ };
+ struct GNUNET_SQ_QueryParam get_params_key_type[] = {
+ GNUNET_SQ_query_param_auto_from_type (key),
+ GNUNET_SQ_query_param_uint32 (&type32),
+ GNUNET_SQ_query_param_uint32 (&limit_off),
+ GNUNET_SQ_query_param_end
+ };
+ struct GNUNET_SQ_QueryParam get_params_key_vhash_type[] = {
+ GNUNET_SQ_query_param_auto_from_type (key),
+ GNUNET_SQ_query_param_auto_from_type (vhash),
+ GNUNET_SQ_query_param_uint32 (&type32),
+ GNUNET_SQ_query_param_uint32 (&limit_off),
+ GNUNET_SQ_query_param_end
+ };
+ struct GNUNET_SQ_QueryParam *count_params;
+ sqlite3_stmt *count_stmt;
+ struct GNUNET_SQ_QueryParam *get_params;
+ sqlite3_stmt *get_stmt;
+
+ if (NULL == vhash)
{
- LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sqlite_prepare");
- proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
- return;
+ if (GNUNET_BLOCK_TYPE_ANY == type)
+ {
+ count_params = count_params_key;
+ count_stmt = plugin->count_key;
+ get_params = get_params_key;
+ get_stmt = plugin->get_key;
+ }
+ else
+ {
+ count_params = count_params_key_type;
+ count_stmt = plugin->count_key_type;
+ get_params = get_params_key_type;
+ get_stmt = plugin->get_key_type;
+ }
}
- sqoff = 1;
- ret =
- sqlite3_bind_blob (stmt, sqoff++, key, sizeof (struct GNUNET_HashCode),
- SQLITE_TRANSIENT);
- if ((vhash != NULL) && (ret == SQLITE_OK))
- ret =
- sqlite3_bind_blob (stmt, sqoff++, vhash, sizeof (struct GNUNET_HashCode),
- SQLITE_TRANSIENT);
- if ((type != 0) && (ret == SQLITE_OK))
- ret = sqlite3_bind_int (stmt, sqoff++, type);
- if (SQLITE_OK != ret)
+ else
+ {
+ if (GNUNET_BLOCK_TYPE_ANY == type)
+ {
+ count_params = count_params_key_vhash;
+ count_stmt = plugin->count_key_vhash;
+ get_params = get_params_key_vhash;
+ get_stmt = plugin->get_key_vhash;
+ }
+ else
+ {
+ count_params = count_params_key_vhash_type;
+ count_stmt = plugin->count_key_vhash_type;
+ get_params = get_params_key_vhash_type;
+ get_stmt = plugin->get_key_vhash_type;
+ }
+ }
+ if (GNUNET_OK !=
+ GNUNET_SQ_bind (count_stmt,
+ count_params))
{
- LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_bind");
- sqlite3_finalize (stmt);
proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
return;
}
- ret = sqlite3_step (stmt);
+ ret = sqlite3_step (count_stmt);
if (ret != SQLITE_ROW)
{
LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
"sqlite_step");
- sqlite3_finalize (stmt);
+ GNUNET_SQ_reset (plugin->dbh,
+ count_stmt);
proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
return;
}
- total = sqlite3_column_int (stmt, 0);
- sqlite3_finalize (stmt);
+ total = sqlite3_column_int (count_stmt,
+ 0);
+ GNUNET_SQ_reset (plugin->dbh,
+ count_stmt);
if (0 == total)
{
proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
return;
}
- limit_off = (int) (offset % total);
- if (limit_off < 0)
- limit_off += total;
- GNUNET_snprintf (scratch, sizeof (scratch),
- "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ "
- "FROM gn090 WHERE hash=?%s%s "
- "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?",
- vhash == NULL ? "" : " AND vhash=?",
- type == 0 ? "" : " AND type=?");
- if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK)
- {
- LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sqlite_prepare");
- proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
- return;
- }
- sqoff = 1;
- ret = sqlite3_bind_blob (stmt, sqoff++, key,
- sizeof (struct GNUNET_HashCode),
- SQLITE_TRANSIENT);
- if ((vhash != NULL) && (ret == SQLITE_OK))
- ret = sqlite3_bind_blob (stmt, sqoff++, vhash,
- sizeof (struct GNUNET_HashCode),
- SQLITE_TRANSIENT);
- if ((type != 0) && (ret == SQLITE_OK))
- ret = sqlite3_bind_int (stmt, sqoff++, type);
- if (ret == SQLITE_OK)
- ret = sqlite3_bind_int64 (stmt, sqoff++, limit_off);
- if (ret != SQLITE_OK)
+ limit_off = (uint32_t) (offset % total);
+ if (GNUNET_OK !=
+ GNUNET_SQ_bind (get_stmt,
+ get_params))
{
- LOG_SQLITE (plugin,
- GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sqlite_bind");
proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
return;
}
- execute_get (plugin, stmt, proc, proc_cls);
- sqlite3_finalize (stmt);
+ execute_get (plugin,
+ get_stmt,
+ proc,
+ proc_cls);
+ GNUNET_SQ_reset (plugin->dbh,
+ get_stmt);
}
@@ -980,13 +1143,17 @@ repl_proc (void *cls,
struct ReplCtx *rc = cls;
int ret;
+ if (GNUNET_SYSERR == rc->have_uid)
+ rc->have_uid = GNUNET_NO;
ret = rc->proc (rc->proc_cls,
key,
- size, data,
+ size,
+ data,
type,
priority,
anonymity,
- expiration, uid);
+ expiration,
+ uid);
if (NULL != key)
{
rc->uid = uid;
@@ -1007,7 +1174,8 @@ repl_proc (void *cls,
* @param proc_cls closure for @a proc
*/
static void
-sqlite_plugin_get_replication (void *cls, PluginDatumProcessor proc,
+sqlite_plugin_get_replication (void *cls,
+ PluginDatumProcessor proc,
void *proc_cls)
{
struct Plugin *plugin = cls;
@@ -1027,24 +1195,21 @@ sqlite_plugin_get_replication (void *cls, PluginDatumProcessor proc,
GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
"datastore-sqlite",
"Getting random block based on replication order.\n");
- rc.have_uid = GNUNET_NO;
- rc.proc = proc;
- rc.proc_cls = proc_cls;
- if (SQLITE_ROW != sqlite3_step (plugin->maxRepl))
+ if (SQLITE_ROW !=
+ sqlite3_step (plugin->maxRepl))
{
- if (SQLITE_OK != sqlite3_reset (plugin->maxRepl))
- LOG_SQLITE (plugin,
- GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sqlite3_reset");
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->maxRepl);
/* DB empty */
proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
return;
}
- repl = sqlite3_column_int (plugin->maxRepl, 0);
- if (SQLITE_OK != sqlite3_reset (plugin->maxRepl))
- LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sqlite3_reset");
- rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
+ repl = sqlite3_column_int (plugin->maxRepl,
+ 0);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->maxRepl);
+ rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
+ UINT64_MAX);
if (GNUNET_OK !=
GNUNET_SQ_bind (plugin->selRepl,
params_sel_repl))
@@ -1052,7 +1217,13 @@ sqlite_plugin_get_replication (void *cls, PluginDatumProcessor proc,
proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
return;
}
- execute_get (plugin, plugin->selRepl, &repl_proc, &rc);
+ rc.have_uid = GNUNET_SYSERR;
+ rc.proc = proc;
+ rc.proc_cls = proc_cls;
+ execute_get (plugin,
+ plugin->selRepl,
+ &repl_proc,
+ &rc);
if (GNUNET_YES == rc.have_uid)
{
if (GNUNET_OK !=
@@ -1062,14 +1233,18 @@ sqlite_plugin_get_replication (void *cls, PluginDatumProcessor proc,
proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
return;
}
- if (SQLITE_DONE != sqlite3_step (plugin->updRepl))
+ if (SQLITE_DONE !=
+ sqlite3_step (plugin->updRepl))
LOG_SQLITE (plugin,
GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
"sqlite3_step");
- if (SQLITE_OK != sqlite3_reset (plugin->updRepl))
- LOG_SQLITE (plugin,
- GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
- "sqlite3_reset");
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->updRepl);
+ }
+ if (GNUNET_SYSERR == rc.have_uid)
+ {
+ /* proc was not called at all so far, do it now. */
+ proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
}
}
@@ -1094,7 +1269,8 @@ sqlite_plugin_get_expiration (void *cls, PluginDatumProcessor proc,
GNUNET_SQ_query_param_end
};
- GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+ "sqlite",
"Getting random block based on expiration and priority order.\n");
now = GNUNET_TIME_absolute_get ();
stmt = plugin->selExpi;
@@ -1131,11 +1307,17 @@ sqlite_plugin_get_keys (void *cls,
int ret;
GNUNET_assert (NULL != proc);
- if (sq_prepare (plugin->dbh, "SELECT hash FROM gn090", &stmt) != SQLITE_OK)
+ if (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT hash FROM gn090",
+ &stmt))
{
- LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
"sqlite_prepare");
- proc (proc_cls, NULL, 0);
+ proc (proc_cls,
+ NULL,
+ 0);
return;
}
while (SQLITE_ROW == (ret = sqlite3_step (stmt)))
@@ -1143,14 +1325,20 @@ sqlite_plugin_get_keys (void *cls,
if (GNUNET_OK ==
GNUNET_SQ_extract_result (stmt,
results))
- proc (proc_cls, &key, 1);
+ proc (proc_cls,
+ &key,
+ 1);
else
GNUNET_break (0);
}
if (SQLITE_DONE != ret)
- LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step");
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR,
+ "sqlite_step");
sqlite3_finalize (stmt);
- proc (proc_cls, NULL, 0);
+ proc (proc_cls,
+ NULL,
+ 0);
}
@@ -1176,7 +1364,8 @@ sqlite_plugin_drop (void *cls)
* @return the size of the database on disk (estimate)
*/
static void
-sqlite_plugin_estimate_size (void *cls, unsigned long long *estimate)
+sqlite_plugin_estimate_size (void *cls,
+ unsigned long long *estimate)
{
struct Plugin *plugin = cls;
sqlite3_stmt *stmt;
@@ -1191,29 +1380,45 @@ sqlite_plugin_estimate_size (void *cls, unsigned long long *estimate)
return;
if (SQLITE_VERSION_NUMBER < 3006000)
{
- GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "datastore-sqlite",
- _
- ("sqlite version to old to determine size, assuming zero\n"));
+ GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
+ "datastore-sqlite",
+ _("sqlite version to old to determine size, assuming zero\n"));
*estimate = 0;
return;
}
- CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "VACUUM", NULL, NULL, ENULL));
CHECK (SQLITE_OK ==
- sqlite3_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL", NULL,
+ sqlite3_exec (plugin->dbh,
+ "VACUUM",
+ NULL,
+ NULL,
+ ENULL));
+ CHECK (SQLITE_OK ==
+ sqlite3_exec (plugin->dbh,
+ "PRAGMA auto_vacuum=INCREMENTAL",
+ NULL,
NULL, ENULL));
- CHECK (SQLITE_OK == sq_prepare (plugin->dbh, "PRAGMA page_count", &stmt));
+ CHECK (SQLITE_OK ==
+ sq_prepare (plugin->dbh,
+ "PRAGMA page_count",
+ &stmt));
if (SQLITE_ROW == sqlite3_step (stmt))
- pages = sqlite3_column_int64 (stmt, 0);
+ pages = sqlite3_column_int64 (stmt,
+ 0);
else
pages = 0;
sqlite3_finalize (stmt);
- CHECK (SQLITE_OK == sq_prepare (plugin->dbh, "PRAGMA page_size", &stmt));
- CHECK (SQLITE_ROW == sqlite3_step (stmt));
+ CHECK (SQLITE_OK ==
+ sq_prepare (plugin->dbh,
+ "PRAGMA page_size",
+ &stmt));
+ CHECK (SQLITE_ROW ==
+ sqlite3_step (stmt));
page_size = sqlite3_column_int64 (stmt, 0);
sqlite3_finalize (stmt);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_("Using sqlite page utilization to estimate payload (%llu pages of size %llu bytes)\n"),
- (unsigned long long) pages, (unsigned long long) page_size);
+ (unsigned long long) pages,
+ (unsigned long long) page_size);
*estimate = pages * page_size;
}
@@ -1231,9 +1436,11 @@ libgnunet_plugin_datastore_sqlite_init (void *cls)
struct GNUNET_DATASTORE_PluginEnvironment *env = cls;
struct GNUNET_DATASTORE_PluginFunctions *api;
- if (plugin.env != NULL)
+ if (NULL != plugin.env)
return NULL; /* can only initialize once! */
- memset (&plugin, 0, sizeof (struct Plugin));
+ memset (&plugin,
+ 0,
+ sizeof (struct Plugin));
plugin.env = env;
if (GNUNET_OK != database_setup (env->cfg, &plugin))
{
@@ -1251,7 +1458,8 @@ libgnunet_plugin_datastore_sqlite_init (void *cls)
api->get_zero_anonymity = &sqlite_plugin_get_zero_anonymity;
api->get_keys = &sqlite_plugin_get_keys;
api->drop = &sqlite_plugin_drop;
- GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "sqlite",
+ GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
+ "sqlite",
_("Sqlite database running\n"));
return api;
}
@@ -1270,13 +1478,12 @@ libgnunet_plugin_datastore_sqlite_done (void *cls)
struct GNUNET_DATASTORE_PluginFunctions *api = cls;
struct Plugin *plugin = api->cls;
- GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+ "sqlite",
"sqlite plugin is done\n");
fn = NULL;
if (plugin->drop_on_shutdown)
fn = GNUNET_strdup (plugin->fn);
- GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
- "Shutting down database\n");
database_shutdown (plugin);
plugin->env = NULL;
GNUNET_free (api);
@@ -1288,9 +1495,6 @@ libgnunet_plugin_datastore_sqlite_done (void *cls)
fn);
GNUNET_free (fn);
}
- GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
- "sqlite",
- "sqlite plugin is finished\n");
return NULL;
}
diff --git a/src/include/gnunet_sq_lib.h b/src/include/gnunet_sq_lib.h
index 4d2510ee56..c196d7767a 100644
--- a/src/include/gnunet_sq_lib.h
+++ b/src/include/gnunet_sq_lib.h
@@ -194,6 +194,17 @@ GNUNET_SQ_bind (sqlite3_stmt *stmt,
/**
+ * Reset @a stmt and log error.
+ *
+ * @param dbh database handle
+ * @param stmt statement to reset
+ */
+void
+GNUNET_SQ_reset (sqlite3 *dbh,
+ sqlite3_stmt *stmt);
+
+
+/**
* Extract data from a Postgres database @a result at row @a row.
*
* @param cls closure
diff --git a/src/revocation/test_revocation.c b/src/revocation/test_revocation.c
index d3bbb879a8..8d55936941 100644
--- a/src/revocation/test_revocation.c
+++ b/src/revocation/test_revocation.c
@@ -104,8 +104,8 @@ revocation_remote_cb (void *cls,
if (GNUNET_NO == is_valid)
{
- fprintf (stderr,
- "Local revocation successful\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Local revocation successful\n");
ok = 0;
GNUNET_SCHEDULER_shutdown ();
return;
@@ -118,8 +118,8 @@ revocation_remote_cb (void *cls,
NULL);
return;
}
- fprintf (stderr,
- "Flooding of revocation failed\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Flooding of revocation failed\n");
ok = 2;
GNUNET_SCHEDULER_shutdown ();
}
@@ -141,8 +141,8 @@ revocation_cb (void *cls,
testpeers[1].revok_handle = NULL;
if (GNUNET_NO == is_valid)
{
- fprintf (stderr,
- "Revocation successful\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Revocation successful\n");
check_revocation (NULL);
}
}
@@ -386,8 +386,8 @@ test_connection (void *cls,
/* We are generating a CLIQUE */
if (NUM_TEST_PEERS * (NUM_TEST_PEERS -1) == links_succeeded)
{
- fprintf (stderr,
- "Testbed connected peers, initializing test\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Testbed connected peers, initializing test\n");
for (c = 0; c < num_peers; c++)
{
testpeers[c].p = peers[c];
@@ -403,8 +403,8 @@ test_connection (void *cls,
}
else
{
- fprintf (stderr,
- "Testbed failed to connect peers\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Testbed failed to connect peers\n");
ok = 5;
GNUNET_SCHEDULER_shutdown ();
return;
diff --git a/src/set/Makefile.am b/src/set/Makefile.am
index cfe95bc1a6..03c258352c 100644
--- a/src/set/Makefile.am
+++ b/src/set/Makefile.am
@@ -51,7 +51,7 @@ gnunet_set_ibf_profiler_LDADD = \
gnunet_service_set_SOURCES = \
gnunet-service-set.c gnunet-service-set.h \
- gnunet-service-set_union.c \
+ gnunet-service-set_union.c gnunet-service-set_union.h \
gnunet-service-set_intersection.c \
ibf.c ibf.h \
gnunet-service-set_union_strata_estimator.c gnunet-service-set_union_strata_estimator.h \
diff --git a/src/set/gnunet-service-set.c b/src/set/gnunet-service-set.c
index 454ad97843..8f1506c6ab 100644
--- a/src/set/gnunet-service-set.c
+++ b/src/set/gnunet-service-set.c
@@ -24,6 +24,8 @@
* @author Christian Grothoff
*/
#include "gnunet-service-set.h"
+#include "gnunet-service-set_union.h"
+#include "gnunet-service-set_intersection.h"
#include "gnunet-service-set_protocol.h"
#include "gnunet_statistics_service.h"
@@ -476,6 +478,7 @@ _GSS_operation_destroy (struct Operation *op,
op->channel = NULL;
GNUNET_CADET_channel_destroy (channel);
}
+
if (GNUNET_YES == gc)
collect_generation_garbage (set);
/* We rely on the channel end handler to free 'op'. When 'op->channel' was NULL,
@@ -682,7 +685,7 @@ client_disconnect_cb (void *cls,
{
struct Operation *curr = op;
op = op->next;
- if ( (GNUNET_YES == curr->is_incoming) &&
+ if ( (GNUNET_YES == curr->is_incoming) &&
(curr->listener == listener) )
incoming_destroy (curr);
}
@@ -733,6 +736,38 @@ incoming_suggest (struct Operation *incoming,
/**
+ * Check a request for a set operation from another peer.
+ *
+ * @param cls the operation state
+ * @param msg the received message
+ * @return #GNUNET_OK if the channel should be kept alive,
+ * #GNUNET_SYSERR to destroy the channel
+ */
+static int
+check_incoming_msg (void *cls,
+ const struct OperationRequestMessage *msg)
+{
+ struct Operation *op = cls;
+ const struct GNUNET_MessageHeader *nested_context;
+
+ /* double operation request */
+ if (NULL != op->spec)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ nested_context = GNUNET_MQ_extract_nested_mh (msg);
+ if ( (NULL != nested_context) &&
+ (ntohs (nested_context->size) > GNUNET_SET_CONTEXT_MESSAGE_MAX_SIZE) )
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
* Handle a request for a set operation from another peer. Checks if we
* have a listener waiting for such a request (and in that case initiates
* asking the listener about accepting the connection). If no listener
@@ -744,42 +779,23 @@ incoming_suggest (struct Operation *incoming,
* our virtual table and subsequent msgs would be routed differently (as
* we then know what type of operation this is).
*
- * @param op the operation state
- * @param mh the received message
+ * @param cls the operation state
+ * @param msg the received message
* @return #GNUNET_OK if the channel should be kept alive,
* #GNUNET_SYSERR to destroy the channel
*/
-static int
-handle_incoming_msg (struct Operation *op,
- const struct GNUNET_MessageHeader *mh)
+static void
+handle_incoming_msg (void *cls,
+ const struct OperationRequestMessage *msg)
{
- const struct OperationRequestMessage *msg;
+ struct Operation *op = cls;
struct Listener *listener = op->listener;
struct OperationSpecification *spec;
const struct GNUNET_MessageHeader *nested_context;
- msg = (const struct OperationRequestMessage *) mh;
GNUNET_assert (GNUNET_YES == op->is_incoming);
- if (GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST != ntohs (mh->type))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- /* double operation request */
- if (NULL != op->spec)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
spec = GNUNET_new (struct OperationSpecification);
nested_context = GNUNET_MQ_extract_nested_mh (msg);
- if ( (NULL != nested_context) &&
- (ntohs (nested_context->size) > GNUNET_SET_CONTEXT_MESSAGE_MAX_SIZE) )
- {
- GNUNET_break_op (0);
- GNUNET_free (spec);
- return GNUNET_SYSERR;
- }
/* Make a copy of the nested_context (application-specific context
information that is opaque to set) so we can pass it to the
listener later on */
@@ -792,7 +808,6 @@ handle_incoming_msg (struct Operation *op,
spec->peer = op->peer;
spec->remote_element_count = ntohl (msg->element_count);
op->spec = spec;
-
listener = op->listener;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received P2P operation request (op %u, port %s) for active listener\n",
@@ -800,7 +815,6 @@ handle_incoming_msg (struct Operation *op,
GNUNET_h2s (&listener->app_id));
incoming_suggest (op,
listener);
- return GNUNET_OK;
}
@@ -1103,9 +1117,11 @@ handle_client_create_set (void *cls,
{
case GNUNET_SET_OPERATION_INTERSECTION:
set->vt = _GSS_intersection_vt ();
+ set->type = OT_INTERSECTION;
break;
case GNUNET_SET_OPERATION_UNION:
set->vt = _GSS_union_vt ();
+ set->type = OT_UNION;
break;
default:
GNUNET_free (set);
@@ -1196,7 +1212,6 @@ channel_new_cb (void *cls,
const struct GNUNET_PeerIdentity *source)
{
static const struct SetVT incoming_vt = {
- .msg_handler = &handle_incoming_msg,
.peer_disconnect = &handle_incoming_disconnect
};
struct Listener *listener = cls;
@@ -1290,60 +1305,6 @@ channel_window_cb (void *cls,
/* FIXME: not implemented, we could do flow control here... */
}
-/**
- * FIXME: hack-job. Migrate to proper handler array use!
- *
- * @param cls local state associated with the channel.
- * @param message The actual message.
- */
-static int
-check_p2p_message (void *cls,
- const struct GNUNET_MessageHeader *message)
-{
- return GNUNET_OK;
-}
-
-
-/**
- * FIXME: hack-job. Migrate to proper handler array use!
- *
- * Functions with this signature are called whenever a message is
- * received via a cadet channel.
- *
- * The msg_handler is a virtual table set in initially either when a peer
- * creates a new channel with us, or once we create a new channel
- * ourselves (evaluate).
- *
- * Once we know the exact type of operation (union/intersection), the vt is
- * replaced with an operation specific instance (_GSS_[op]_vt).
- *
- * @param cls local state associated with the channel.
- * @param message The actual message.
- */
-static void
-handle_p2p_message (void *cls,
- const struct GNUNET_MessageHeader *message)
-{
- struct Operation *op = cls;
- int ret;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Dispatching cadet message (type: %u)\n",
- ntohs (message->type));
- /* do this before the handler, as the handler might kill the channel */
- GNUNET_CADET_receive_done (op->channel);
- if (NULL != op->vt)
- ret = op->vt->msg_handler (op,
- message);
- else
- ret = GNUNET_SYSERR;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Handled cadet message (type: %u)\n",
- ntohs (message->type));
- if (GNUNET_OK != ret)
- GNUNET_CADET_channel_destroy (op->channel);
-}
-
/**
* Called when a client wants to create a new listener.
@@ -1357,66 +1318,66 @@ handle_client_listen (void *cls,
{
struct GNUNET_SERVICE_Client *client = cls;
struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_var_size (incoming_msg,
GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST,
- struct GNUNET_MessageHeader,
+ struct OperationRequestMessage,
NULL),
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_var_size (union_p2p_ibf,
GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF,
- struct GNUNET_MessageHeader,
+ struct IBFMessage,
NULL),
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_var_size (union_p2p_elements,
GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS,
- struct GNUNET_MessageHeader,
+ struct GNUNET_SET_ElementMessage,
NULL),
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_var_size (union_p2p_offer,
GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER,
struct GNUNET_MessageHeader,
NULL),
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_var_size (union_p2p_inquiry,
GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY,
- struct GNUNET_MessageHeader,
+ struct InquiryMessage,
NULL),
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_var_size (union_p2p_demand,
GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND,
struct GNUNET_MessageHeader,
NULL),
- GNUNET_MQ_hd_var_size (p2p_message,
- GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE,
- struct GNUNET_MessageHeader,
- NULL),
- GNUNET_MQ_hd_var_size (p2p_message,
- GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE,
- struct GNUNET_MessageHeader,
- NULL),
- GNUNET_MQ_hd_var_size (p2p_message,
- GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL,
- struct GNUNET_MessageHeader,
- NULL),
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_fixed_size (union_p2p_done,
+ GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE,
+ struct GNUNET_MessageHeader,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (union_p2p_full_done,
+ GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE,
+ struct GNUNET_MessageHeader,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (union_p2p_request_full,
+ GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL,
+ struct GNUNET_MessageHeader,
+ NULL),
+ GNUNET_MQ_hd_var_size (union_p2p_strata_estimator,
GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE,
- struct GNUNET_MessageHeader,
+ struct StrataEstimatorMessage,
NULL),
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_var_size (union_p2p_strata_estimator,
GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC,
- struct GNUNET_MessageHeader,
+ struct StrataEstimatorMessage,
NULL),
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_var_size (union_p2p_full_element,
GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT,
- struct GNUNET_MessageHeader,
+ struct GNUNET_SET_ElementMessage,
NULL),
- GNUNET_MQ_hd_var_size (p2p_message,
- GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO,
- struct GNUNET_MessageHeader,
- NULL),
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_fixed_size (intersection_p2p_element_info,
+ GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO,
+ struct IntersectionElementInfoMessage,
+ NULL),
+ GNUNET_MQ_hd_var_size (intersection_p2p_bf,
GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF,
- struct GNUNET_MessageHeader,
- NULL),
- GNUNET_MQ_hd_var_size (p2p_message,
- GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE,
- struct GNUNET_MessageHeader,
+ struct BFMessage,
NULL),
+ GNUNET_MQ_hd_fixed_size (intersection_p2p_done,
+ GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE,
+ struct IntersectionDoneMessage,
+ NULL),
GNUNET_MQ_handler_end ()
};
struct Listener *listener;
@@ -1623,66 +1584,66 @@ handle_client_evaluate (void *cls,
struct GNUNET_SERVICE_Client *client = cls;
struct Operation *op = GNUNET_new (struct Operation);
const struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_var_size (incoming_msg,
GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST,
- struct GNUNET_MessageHeader,
+ struct OperationRequestMessage,
op),
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_var_size (union_p2p_ibf,
GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF,
- struct GNUNET_MessageHeader,
+ struct IBFMessage,
op),
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_var_size (union_p2p_elements,
GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS,
- struct GNUNET_MessageHeader,
+ struct GNUNET_SET_ElementMessage,
op),
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_var_size (union_p2p_offer,
GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER,
struct GNUNET_MessageHeader,
op),
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_var_size (union_p2p_inquiry,
GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY,
- struct GNUNET_MessageHeader,
+ struct InquiryMessage,
op),
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_var_size (union_p2p_demand,
GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND,
struct GNUNET_MessageHeader,
op),
- GNUNET_MQ_hd_var_size (p2p_message,
- GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE,
- struct GNUNET_MessageHeader,
- op),
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_fixed_size (union_p2p_done,
+ GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE,
+ struct GNUNET_MessageHeader,
+ op),
+ GNUNET_MQ_hd_fixed_size (union_p2p_full_done,
+ GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE,
+ struct GNUNET_MessageHeader,
+ op),
+ GNUNET_MQ_hd_fixed_size (union_p2p_request_full,
+ GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL,
+ struct GNUNET_MessageHeader,
+ op),
+ GNUNET_MQ_hd_var_size (union_p2p_strata_estimator,
GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE,
- struct GNUNET_MessageHeader,
+ struct StrataEstimatorMessage,
op),
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_var_size (union_p2p_strata_estimator,
GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC,
- struct GNUNET_MessageHeader,
- op),
- GNUNET_MQ_hd_var_size (p2p_message,
- GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE,
- struct GNUNET_MessageHeader,
- op),
- GNUNET_MQ_hd_var_size (p2p_message,
- GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL,
- struct GNUNET_MessageHeader,
+ struct StrataEstimatorMessage,
op),
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_var_size (union_p2p_full_element,
GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT,
- struct GNUNET_MessageHeader,
- op),
- GNUNET_MQ_hd_var_size (p2p_message,
- GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO,
- struct GNUNET_MessageHeader,
+ struct GNUNET_SET_ElementMessage,
op),
- GNUNET_MQ_hd_var_size (p2p_message,
+ GNUNET_MQ_hd_fixed_size (intersection_p2p_element_info,
+ GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO,
+ struct IntersectionElementInfoMessage,
+ op),
+ GNUNET_MQ_hd_var_size (intersection_p2p_bf,
GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF,
- struct GNUNET_MessageHeader,
- op),
- GNUNET_MQ_hd_var_size (p2p_message,
- GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE,
- struct GNUNET_MessageHeader,
+ struct BFMessage,
op),
+ GNUNET_MQ_hd_fixed_size (intersection_p2p_done,
+ GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE,
+ struct IntersectionDoneMessage,
+ op),
GNUNET_MQ_handler_end ()
};
struct Set *set;
@@ -1717,7 +1678,7 @@ handle_client_evaluate (void *cls,
// mutations won't interfer with the running operation.
op->generation_created = set->current_generation;
advance_generation (set);
-
+ op->type = set->type;
op->vt = set->vt;
GNUNET_CONTAINER_DLL_insert (set->ops_head,
set->ops_tail,
@@ -1886,9 +1847,11 @@ handle_client_copy_lazy_connect (void *cls,
{
case GNUNET_SET_OPERATION_INTERSECTION:
set->vt = _GSS_intersection_vt ();
+ set->type = OT_INTERSECTION;
break;
case GNUNET_SET_OPERATION_UNION:
set->vt = _GSS_union_vt ();
+ set->type = OT_UNION;
break;
default:
GNUNET_assert (0);
@@ -2057,6 +2020,7 @@ handle_client_accept (void *cls,
advance_generation (set);
op->vt = set->vt;
+ op->type = set->type;
op->vt->accept (op);
GNUNET_SERVICE_client_continue (client);
}
diff --git a/src/set/gnunet-service-set.h b/src/set/gnunet-service-set.h
index 68d8fe81f6..c981430ef0 100644
--- a/src/set/gnunet-service-set.h
+++ b/src/set/gnunet-service-set.h
@@ -213,20 +213,6 @@ typedef void
/**
- * Signature of functions that implement the message handling for
- * the different set operations.
- *
- * @param op operation state
- * @param msg received message
- * @return #GNUNET_OK on success, #GNUNET_SYSERR to
- * destroy the operation and the tunnel
- */
-typedef int
-(*MsgHandlerImpl) (struct Operation *op,
- const struct GNUNET_MessageHeader *msg);
-
-
-/**
* Signature of functions that implement operation cancellation
*
* @param op operation state
@@ -276,11 +262,6 @@ struct SetVT
DestroySetImpl destroy_set;
/**
- * Callback for handling operation-specific messages.
- */
- MsgHandlerImpl msg_handler;
-
- /**
* Callback for handling the remote peer's disconnect.
*/
PeerDisconnectImpl peer_disconnect;
@@ -364,6 +345,27 @@ struct Listener;
/**
+ * Possible set operations.
+ */
+enum OperationType {
+ /**
+ * Operation type unknown.
+ */
+ OT_UNKNOWN = 0,
+
+ /**
+ * We are performing a union.
+ */
+ OT_UNION,
+
+ /**
+ * We are performing an intersection.
+ */
+ OT_INTERSECTION
+};
+
+
+/**
* Operation context used to execute a set operation.
*/
struct Operation
@@ -427,6 +429,11 @@ struct Operation
struct GNUNET_SCHEDULER_Task *timeout_task;
/**
+ * What type of operation is this?
+ */
+ enum OperationType type;
+
+ /**
* Unique request id for the request from a remote peer, sent to the
* client, which will accept or reject the request. Set to '0' iff
* the request has not been suggested yet.
@@ -582,6 +589,11 @@ struct Set
struct Operation *ops_tail;
/**
+ * What type of operation is this set for?
+ */
+ enum OperationType type;
+
+ /**
* Current generation, that is, number of previously executed
* operations and lazy copies on the underlying set content.
*/
diff --git a/src/set/gnunet-service-set_intersection.c b/src/set/gnunet-service-set_intersection.c
index 9fe1eabe64..b298f7b41a 100644
--- a/src/set/gnunet-service-set_intersection.c
+++ b/src/set/gnunet-service-set_intersection.c
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet
- Copyright (C) 2013, 2014 GNUnet e.V.
+ Copyright (C) 2013-2017 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
@@ -28,6 +28,7 @@
#include "gnunet-service-set.h"
#include "gnunet_block_lib.h"
#include "gnunet-service-set_protocol.h"
+#include "gnunet-service-set_intersection.h"
#include <gcrypt.h>
@@ -550,6 +551,8 @@ send_remaining_elements (void *cls)
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Sending done and destroy because iterator ran out\n");
op->keep--;
+ GNUNET_CONTAINER_multihashmap_iterator_destroy (op->state->full_result_iter);
+ op->state->full_result_iter = NULL;
send_client_done_and_destroy (op);
return;
}
@@ -627,9 +630,6 @@ process_bf (struct Operation *op)
case PHASE_COUNT_SENT:
/* This is the first BF being sent, build our initial map with
filtering in place */
- op->state->my_elements
- = GNUNET_CONTAINER_multihashmap_create (op->spec->remote_element_count,
- GNUNET_YES);
op->state->my_element_count = 0;
GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->content->elements,
&filtered_map_initialization,
@@ -665,41 +665,53 @@ process_bf (struct Operation *op)
/**
+ * Check an BF message from a remote peer.
+ *
+ * @param cls the intersection operation
+ * @param msg the header of the message
+ * @return #GNUNET_OK if @a msg is well-formed
+ */
+int
+check_intersection_p2p_bf (void *cls,
+ const struct BFMessage *msg)
+{
+ struct Operation *op = cls;
+
+ if (OT_INTERSECTION != op->type)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
* Handle an BF message from a remote peer.
*
* @param cls the intersection operation
- * @param mh the header of the message
+ * @param msg the header of the message
*/
-static void
-handle_p2p_bf (void *cls,
- const struct GNUNET_MessageHeader *mh)
+void
+handle_intersection_p2p_bf (void *cls,
+ const struct BFMessage *msg)
{
struct Operation *op = cls;
- const struct BFMessage *msg;
uint32_t bf_size;
uint32_t chunk_size;
uint32_t bf_bits_per_element;
- uint16_t msize;
- msize = htons (mh->size);
- if (msize < sizeof (struct BFMessage))
- {
- GNUNET_break_op (0);
- fail_intersection_operation (op);
- return;
- }
- msg = (const struct BFMessage *) mh;
switch (op->state->phase)
{
case PHASE_INITIAL:
GNUNET_break_op (0);
fail_intersection_operation (op);
- break;
+ return;
case PHASE_COUNT_SENT:
case PHASE_BF_EXCHANGE:
bf_size = ntohl (msg->bloomfilter_total_length);
bf_bits_per_element = ntohl (msg->bits_per_element);
- chunk_size = msize - sizeof (struct BFMessage);
+ chunk_size = htons (msg->header.size) - sizeof (struct BFMessage);
op->state->other_xor = msg->element_xor_hash;
if (bf_size == chunk_size)
{
@@ -717,7 +729,7 @@ handle_p2p_bf (void *cls,
op->state->salt = ntohl (msg->sender_mutator);
op->spec->remote_element_count = ntohl (msg->sender_element_count);
process_bf (op);
- return;
+ break;
}
/* multipart chunk */
if (NULL == op->state->bf_data)
@@ -764,8 +776,9 @@ handle_p2p_bf (void *cls,
default:
GNUNET_break_op (0);
fail_intersection_operation (op);
- break;
+ return;
}
+ GNUNET_CADET_receive_done (op->channel);
}
@@ -836,6 +849,7 @@ static void
begin_bf_exchange (struct Operation *op)
{
op->state->phase = PHASE_BF_EXCHANGE;
+ GNUNET_assert (NULL == op->state->my_elements);
op->state->my_elements
= GNUNET_CONTAINER_multihashmap_create (op->state->my_element_count,
GNUNET_YES);
@@ -853,20 +867,18 @@ begin_bf_exchange (struct Operation *op)
* @param cls the intersection operation
* @param mh the header of the message
*/
-static void
-handle_p2p_element_info (void *cls,
- const struct GNUNET_MessageHeader *mh)
+void
+handle_intersection_p2p_element_info (void *cls,
+ const struct IntersectionElementInfoMessage *msg)
{
struct Operation *op = cls;
- const struct IntersectionElementInfoMessage *msg;
- if (ntohs (mh->size) != sizeof (struct IntersectionElementInfoMessage))
+ if (OT_INTERSECTION != op->type)
{
GNUNET_break_op (0);
fail_intersection_operation(op);
return;
}
- msg = (const struct IntersectionElementInfoMessage *) mh;
op->spec->remote_element_count = ntohl (msg->sender_element_count);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received remote element count (%u), I have %u\n",
@@ -884,6 +896,7 @@ handle_p2p_element_info (void *cls,
}
GNUNET_break (NULL == op->state->remote_bf);
begin_bf_exchange (op);
+ GNUNET_CADET_receive_done (op->channel);
}
@@ -955,28 +968,26 @@ filter_all (void *cls,
* @param cls the intersection operation
* @param mh the message
*/
-static void
-handle_p2p_done (void *cls,
- const struct GNUNET_MessageHeader *mh)
+void
+handle_intersection_p2p_done (void *cls,
+ const struct IntersectionDoneMessage *idm)
{
struct Operation *op = cls;
- const struct IntersectionDoneMessage *idm;
- if (PHASE_BF_EXCHANGE != op->state->phase)
+ if (OT_INTERSECTION != op->type)
{
- /* wrong phase to conclude? FIXME: Or should we allow this
- if the other peer has _initially_ already an empty set? */
GNUNET_break_op (0);
- fail_intersection_operation (op);
+ fail_intersection_operation(op);
return;
}
- if (ntohs (mh->size) != sizeof (struct IntersectionDoneMessage))
+ if (PHASE_BF_EXCHANGE != op->state->phase)
{
+ /* wrong phase to conclude? FIXME: Or should we allow this
+ if the other peer has _initially_ already an empty set? */
GNUNET_break_op (0);
fail_intersection_operation (op);
return;
}
- idm = (const struct IntersectionDoneMessage *) mh;
if (0 == ntohl (idm->final_element_count))
{
/* other peer determined empty set is the intersection,
@@ -1000,6 +1011,7 @@ handle_p2p_done (void *cls,
op->state->my_element_count);
op->state->phase = PHASE_FINISHED;
finish_and_destroy (op);
+ GNUNET_CADET_receive_done (op->channel);
}
@@ -1064,11 +1076,11 @@ intersection_accept (struct Operation *op)
op->state->phase = PHASE_INITIAL;
op->state->my_element_count
= op->spec->set->state->current_set_element_count;
+ GNUNET_assert (NULL == op->state->my_elements);
op->state->my_elements
- = GNUNET_CONTAINER_multihashmap_create
- (GNUNET_MIN (op->state->my_element_count,
- op->spec->remote_element_count),
- GNUNET_YES);
+ = GNUNET_CONTAINER_multihashmap_create (GNUNET_MIN (op->state->my_element_count,
+ op->spec->remote_element_count),
+ GNUNET_YES);
if (op->spec->remote_element_count < op->state->my_element_count)
{
/* If the other peer (Alice) has fewer elements than us (Bob),
@@ -1083,43 +1095,6 @@ intersection_accept (struct Operation *op)
/**
- * Dispatch messages for a intersection operation.
- *
- * @param op the state of the intersection evaluate operation
- * @param mh the received message
- * @return #GNUNET_SYSERR if the tunnel should be disconnected,
- * #GNUNET_OK otherwise
- */
-static int
-intersection_handle_p2p_message (struct Operation *op,
- const struct GNUNET_MessageHeader *mh)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received p2p message (t: %u, s: %u)\n",
- ntohs (mh->type), ntohs (mh->size));
- switch (ntohs (mh->type))
- {
- /* this message handler is not active until after we received an
- * operation request message, thus the ops request is not handled here
- */
- case GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO:
- handle_p2p_element_info (op, mh);
- break;
- case GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF:
- handle_p2p_bf (op, mh);
- break;
- case GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE:
- handle_p2p_done (op, mh);
- break;
- default:
- /* something wrong with cadet's message handlers? */
- GNUNET_assert (0);
- }
- return GNUNET_OK;
-}
-
-
-/**
* Handler for peer-disconnects, notifies the client about the aborted
* operation. If we did not expect anything from the other peer, we
* gracefully terminate the operation.
@@ -1168,6 +1143,11 @@ intersection_op_cancel (struct Operation *op)
GNUNET_CONTAINER_multihashmap_destroy (op->state->my_elements);
op->state->my_elements = NULL;
}
+ if (NULL != op->state->full_result_iter)
+ {
+ GNUNET_CONTAINER_multihashmap_iterator_destroy (op->state->full_result_iter);
+ op->state->full_result_iter = NULL;
+ }
GNUNET_free (op->state);
op->state = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1245,7 +1225,6 @@ _GSS_intersection_vt ()
{
static const struct SetVT intersection_vt = {
.create = &intersection_set_create,
- .msg_handler = &intersection_handle_p2p_message,
.add = &intersection_add,
.remove = &intersection_remove,
.destroy_set = &intersection_set_destroy,
diff --git a/src/set/gnunet-service-set_union.c b/src/set/gnunet-service-set_union.c
index b5b6020741..1ff3d77164 100644
--- a/src/set/gnunet-service-set_union.c
+++ b/src/set/gnunet-service-set_union.c
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet
- Copyright (C) 2013-2016 GNUnet e.V.
+ Copyright (C) 2013-2017 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
@@ -19,15 +19,16 @@
*/
/**
* @file set/gnunet-service-set_union.c
-
* @brief two-peer set operations
* @author Florian Dold
+ * @author Christian Grothoff
*/
#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_statistics_service.h"
#include "gnunet-service-set.h"
#include "ibf.h"
+#include "gnunet-service-set_union.h"
#include "gnunet-service-set_union_strata_estimator.h"
#include "gnunet-service-set_protocol.h"
#include <gcrypt.h>
@@ -786,11 +787,18 @@ send_element_iterator (void *cls,
struct GNUNET_SET_Element *el = &ee->element;
struct GNUNET_MQ_Envelope *ev;
-
- ev = GNUNET_MQ_msg_extra (emsg, el->size, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT);
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Sending element %s\n",
+ GNUNET_h2s (key));
+ ev = GNUNET_MQ_msg_extra (emsg,
+ el->size,
+ GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT);
emsg->element_type = htons (el->element_type);
- GNUNET_memcpy (&emsg[1], el->data, el->size);
- GNUNET_MQ_send (op->mq, ev);
+ GNUNET_memcpy (&emsg[1],
+ el->data,
+ el->size);
+ GNUNET_MQ_send (op->mq,
+ ev);
return GNUNET_YES;
}
@@ -801,11 +809,14 @@ send_full_set (struct Operation *op)
struct GNUNET_MQ_Envelope *ev;
op->state->phase = PHASE_FULL_SENDING;
-
+ /* FIXME: use a more memory-friendly way of doing this with an
+ iterator, just as we do in the non-full case! */
(void) GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->content->elements,
- &send_element_iterator, op);
+ &send_element_iterator,
+ op);
ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE);
- GNUNET_MQ_send (op->mq, ev);
+ GNUNET_MQ_send (op->mq,
+ ev);
}
@@ -813,42 +824,56 @@ send_full_set (struct Operation *op)
* Handle a strata estimator from a remote peer
*
* @param cls the union operation
- * @param mh the message
- * @param is_compressed #GNUNET_YES if the estimator is compressed
- * @return #GNUNET_SYSERR if the tunnel should be disconnected,
- * #GNUNET_OK otherwise
+ * @param msg the message
*/
-static int
-handle_p2p_strata_estimator (void *cls,
- const struct GNUNET_MessageHeader *mh,
- int is_compressed)
+int
+check_union_p2p_strata_estimator (void *cls,
+ const struct StrataEstimatorMessage *msg)
{
struct Operation *op = cls;
- struct StrataEstimator *remote_se;
- struct StrataEstimatorMessage *msg = (void *) mh;
- unsigned int diff;
- uint64_t other_size;
+ int is_compressed;
size_t len;
- GNUNET_STATISTICS_update (_GSS_statistics,
- "# bytes of SE received",
- ntohs (mh->size),
- GNUNET_NO);
-
if (op->state->phase != PHASE_EXPECT_SE)
{
GNUNET_break (0);
- fail_union_operation (op);
return GNUNET_SYSERR;
}
- len = ntohs (mh->size) - sizeof (struct StrataEstimatorMessage);
+ is_compressed = (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC == htons (msg->header.type));
+ len = ntohs (msg->header.size) - sizeof (struct StrataEstimatorMessage);
if ( (GNUNET_NO == is_compressed) &&
(len != SE_STRATA_COUNT * SE_IBF_SIZE * IBF_BUCKET_SIZE) )
{
- fail_union_operation (op);
GNUNET_break (0);
return GNUNET_SYSERR;
}
+ return GNUNET_OK;
+}
+
+
+/**
+ * Handle a strata estimator from a remote peer
+ *
+ * @param cls the union operation
+ * @param msg the message
+ */
+void
+handle_union_p2p_strata_estimator (void *cls,
+ const struct StrataEstimatorMessage *msg)
+{
+ struct Operation *op = cls;
+ struct StrataEstimator *remote_se;
+ unsigned int diff;
+ uint64_t other_size;
+ size_t len;
+ int is_compressed;
+
+ is_compressed = (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC == htons (msg->header.type));
+ GNUNET_STATISTICS_update (_GSS_statistics,
+ "# bytes of SE received",
+ ntohs (msg->header.size),
+ GNUNET_NO);
+ len = ntohs (msg->header.size) - sizeof (struct StrataEstimatorMessage);
other_size = GNUNET_ntohll (msg->set_size);
remote_se = strata_estimator_create (SE_STRATA_COUNT,
SE_IBF_SIZE,
@@ -857,7 +882,7 @@ handle_p2p_strata_estimator (void *cls,
{
/* insufficient resources, fail */
fail_union_operation (op);
- return GNUNET_SYSERR;
+ return;
}
if (GNUNET_OK !=
strata_estimator_read (&msg[1],
@@ -866,18 +891,16 @@ handle_p2p_strata_estimator (void *cls,
remote_se))
{
/* decompression failed */
- fail_union_operation (op);
strata_estimator_destroy (remote_se);
- return GNUNET_SYSERR;
+ fail_union_operation (op);
+ return;
}
GNUNET_assert (NULL != op->state->se);
diff = strata_estimator_difference (remote_se,
op->state->se);
if (diff > 200)
- diff = diff * 3 / 2;
-
-
+ diff = diff * 3 / 2;
strata_estimator_destroy (remote_se);
strata_estimator_destroy (op->state->se);
@@ -885,12 +908,14 @@ handle_p2p_strata_estimator (void *cls,
LOG (GNUNET_ERROR_TYPE_DEBUG,
"got se diff=%d, using ibf size %d\n",
diff,
- 1<<get_order_from_difference (diff));
+ 1U << get_order_from_difference (diff));
{
char *set_debug;
+
set_debug = getenv ("GNUNET_SET_BENCHMARK");
- if ( (NULL != set_debug) && (0 == strcmp (set_debug, "1")) )
+ if ( (NULL != set_debug) &&
+ (0 == strcmp (set_debug, "1")) )
{
FILE *f = fopen ("set.log", "a");
fprintf (f, "%llu\n", (unsigned long long) diff);
@@ -898,34 +923,41 @@ handle_p2p_strata_estimator (void *cls,
}
}
- if ((GNUNET_YES == op->spec->byzantine) && (other_size < op->spec->byzantine_lower_bound))
+ if ( (GNUNET_YES == op->spec->byzantine) &&
+ (other_size < op->spec->byzantine_lower_bound) )
{
GNUNET_break (0);
fail_union_operation (op);
- return GNUNET_SYSERR;
+ return;
}
-
- if ( (GNUNET_YES == op->spec->force_full) || (diff > op->state->initial_size / 4))
+ if ( (GNUNET_YES == op->spec->force_full) ||
+ (diff > op->state->initial_size / 4) ||
+ (0 == other_size) )
{
LOG (GNUNET_ERROR_TYPE_INFO,
- "Sending full set (diff=%d, own set=%u)\n",
+ "Deciding to go for full set transmission (diff=%d, own set=%u)\n",
diff,
op->state->initial_size);
GNUNET_STATISTICS_update (_GSS_statistics,
"# of full sends",
1,
GNUNET_NO);
- if (op->state->initial_size <= other_size)
+ if ( (op->state->initial_size <= other_size) ||
+ (0 == other_size) )
{
send_full_set (op);
}
else
{
struct GNUNET_MQ_Envelope *ev;
+
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Telling other peer that we expect its full set\n");
op->state->phase = PHASE_EXPECT_IBF;
ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL);
- GNUNET_MQ_send (op->mq, ev);
+ GNUNET_MQ_send (op->mq,
+ ev);
}
}
else
@@ -942,11 +974,10 @@ handle_p2p_strata_estimator (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to send IBF, closing connection\n");
fail_union_operation (op);
- return GNUNET_SYSERR;
+ return;
}
}
-
- return GNUNET_OK;
+ GNUNET_CADET_receive_done (op->channel);
}
@@ -1164,99 +1195,116 @@ decode_and_send (struct Operation *op)
/**
- * Handle an IBF message from a remote peer.
+ * Check an IBF message from a remote peer.
*
* Reassemble the IBF from multiple pieces, and
* process the whole IBF once possible.
*
* @param cls the union operation
- * @param mh the header of the message
- * @return #GNUNET_SYSERR if the tunnel should be disconnected,
- * #GNUNET_OK otherwise
+ * @param msg the header of the message
+ * @return #GNUNET_OK if @a msg is well-formed
*/
-static int
-handle_p2p_ibf (void *cls,
- const struct GNUNET_MessageHeader *mh)
+int
+check_union_p2p_ibf (void *cls,
+ const struct IBFMessage *msg)
{
struct Operation *op = cls;
- const struct IBFMessage *msg;
unsigned int buckets_in_message;
- if (ntohs (mh->size) < sizeof (struct IBFMessage))
+ if (OT_UNION != op->type)
{
GNUNET_break_op (0);
- fail_union_operation (op);
return GNUNET_SYSERR;
}
- msg = (const struct IBFMessage *) mh;
- if ( (op->state->phase == PHASE_INVENTORY_PASSIVE) ||
- (op->state->phase == PHASE_EXPECT_IBF) )
+ buckets_in_message = (ntohs (msg->header.size) - sizeof *msg) / IBF_BUCKET_SIZE;
+ if (0 == buckets_in_message)
{
- op->state->phase = PHASE_EXPECT_IBF_CONT;
- GNUNET_assert (NULL == op->state->remote_ibf);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Creating new ibf of size %u\n",
- 1 << msg->order);
- op->state->remote_ibf = ibf_create (1<<msg->order, SE_IBF_HASH_NUM);
- op->state->salt_receive = ntohl (msg->salt);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving new IBF with salt %u\n", op->state->salt_receive);
- if (NULL == op->state->remote_ibf)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse remote IBF, closing connection\n");
- fail_union_operation (op);
- return GNUNET_SYSERR;
- }
- op->state->ibf_buckets_received = 0;
- if (0 != ntohl (msg->offset))
- {
- GNUNET_break_op (0);
- fail_union_operation (op);
- return GNUNET_SYSERR;
- }
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if ((ntohs (msg->header.size) - sizeof *msg) != buckets_in_message * IBF_BUCKET_SIZE)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
}
- else if (op->state->phase == PHASE_EXPECT_IBF_CONT)
+ if (op->state->phase == PHASE_EXPECT_IBF_CONT)
{
if (ntohl (msg->offset) != op->state->ibf_buckets_received)
{
GNUNET_break_op (0);
- fail_union_operation (op);
return GNUNET_SYSERR;
}
if (1<<msg->order != op->state->remote_ibf->size)
{
GNUNET_break_op (0);
- fail_union_operation (op);
return GNUNET_SYSERR;
}
if (ntohl (msg->salt) != op->state->salt_receive)
{
GNUNET_break_op (0);
- fail_union_operation (op);
return GNUNET_SYSERR;
}
}
- else
+ else if ( (op->state->phase != PHASE_INVENTORY_PASSIVE) &&
+ (op->state->phase != PHASE_EXPECT_IBF) )
{
- GNUNET_assert (0);
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
}
- buckets_in_message = (ntohs (msg->header.size) - sizeof *msg) / IBF_BUCKET_SIZE;
+ return GNUNET_OK;
+}
- if (0 == buckets_in_message)
+
+/**
+ * Handle an IBF message from a remote peer.
+ *
+ * Reassemble the IBF from multiple pieces, and
+ * process the whole IBF once possible.
+ *
+ * @param cls the union operation
+ * @param msg the header of the message
+ */
+void
+handle_union_p2p_ibf (void *cls,
+ const struct IBFMessage *msg)
+{
+ struct Operation *op = cls;
+ unsigned int buckets_in_message;
+
+ buckets_in_message = (ntohs (msg->header.size) - sizeof *msg) / IBF_BUCKET_SIZE;
+ if ( (op->state->phase == PHASE_INVENTORY_PASSIVE) ||
+ (op->state->phase == PHASE_EXPECT_IBF) )
{
- GNUNET_break_op (0);
- fail_union_operation (op);
- return GNUNET_SYSERR;
+ op->state->phase = PHASE_EXPECT_IBF_CONT;
+ GNUNET_assert (NULL == op->state->remote_ibf);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating new ibf of size %u\n",
+ 1 << msg->order);
+ op->state->remote_ibf = ibf_create (1<<msg->order, SE_IBF_HASH_NUM);
+ op->state->salt_receive = ntohl (msg->salt);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Receiving new IBF with salt %u\n",
+ op->state->salt_receive);
+ if (NULL == op->state->remote_ibf)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse remote IBF, closing connection\n");
+ fail_union_operation (op);
+ return;
+ }
+ op->state->ibf_buckets_received = 0;
+ if (0 != ntohl (msg->offset))
+ {
+ GNUNET_break_op (0);
+ fail_union_operation (op);
+ return;
+ }
}
-
- if ((ntohs (msg->header.size) - sizeof *msg) != buckets_in_message * IBF_BUCKET_SIZE)
+ else
{
- GNUNET_break_op (0);
- fail_union_operation (op);
- return GNUNET_SYSERR;
+ GNUNET_assert (op->state->phase == PHASE_EXPECT_IBF_CONT);
}
-
GNUNET_assert (NULL != op->state->remote_ibf);
ibf_read_slice (&msg[1],
@@ -1276,10 +1324,11 @@ handle_p2p_ibf (void *cls,
/* Internal error, best we can do is shut down */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to decode IBF, closing connection\n");
- return GNUNET_SYSERR;
+ fail_union_operation (op);
+ return;
}
}
- return GNUNET_OK;
+ GNUNET_CADET_receive_done (op->channel);
}
@@ -1343,6 +1392,11 @@ send_done_and_destroy (void *cls)
}
+/**
+ * Tests if the operation is finished, and if so notify.
+ *
+ * @param op operation to check
+ */
static void
maybe_finish (struct Operation *op)
{
@@ -1382,46 +1436,59 @@ maybe_finish (struct Operation *op)
/**
- * Handle an element message from a remote peer.
- * Sent by the other peer either because we decoded an IBF and placed a demand,
- * or because the other peer switched to full set transmission.
+ * Check an element message from a remote peer.
*
* @param cls the union operation
- * @param mh the message
+ * @param emsg the message
*/
-static void
-handle_p2p_elements (void *cls,
- const struct GNUNET_MessageHeader *mh)
+int
+check_union_p2p_elements (void *cls,
+ const struct GNUNET_SET_ElementMessage *emsg)
{
struct Operation *op = cls;
- struct ElementEntry *ee;
- const struct GNUNET_SET_ElementMessage *emsg;
- uint16_t element_size;
- if (0 == GNUNET_CONTAINER_multihashmap_size (op->state->demanded_hashes))
+ if (OT_UNION != op->type)
{
GNUNET_break_op (0);
- fail_union_operation (op);
- return;
+ return GNUNET_SYSERR;
}
- if (ntohs (mh->size) < sizeof (struct GNUNET_SET_ElementMessage))
+ if (0 == GNUNET_CONTAINER_multihashmap_size (op->state->demanded_hashes))
{
GNUNET_break_op (0);
- fail_union_operation (op);
- return;
+ return GNUNET_SYSERR;
}
+ return GNUNET_OK;
+}
+
- emsg = (const struct GNUNET_SET_ElementMessage *) mh;
+/**
+ * Handle an element message from a remote peer.
+ * Sent by the other peer either because we decoded an IBF and placed a demand,
+ * or because the other peer switched to full set transmission.
+ *
+ * @param cls the union operation
+ * @param emsg the message
+ */
+void
+handle_union_p2p_elements (void *cls,
+ const struct GNUNET_SET_ElementMessage *emsg)
+{
+ struct Operation *op = cls;
+ struct ElementEntry *ee;
+ struct KeyEntry *ke;
+ uint16_t element_size;
- element_size = ntohs (mh->size) - sizeof (struct GNUNET_SET_ElementMessage);
+ element_size = ntohs (emsg->header.size) - sizeof (struct GNUNET_SET_ElementMessage);
ee = GNUNET_malloc (sizeof (struct ElementEntry) + element_size);
- GNUNET_memcpy (&ee[1], &emsg[1], element_size);
+ GNUNET_memcpy (&ee[1],
+ &emsg[1],
+ element_size);
ee->element.size = element_size;
ee->element.data = &ee[1];
ee->element.element_type = ntohs (emsg->element_type);
ee->remote = GNUNET_YES;
- GNUNET_SET_element_hash (&ee->element, &ee->element_hash);
-
+ GNUNET_SET_element_hash (&ee->element,
+ &ee->element_hash);
if (GNUNET_NO ==
GNUNET_CONTAINER_multihashmap_remove (op->state->demanded_hashes,
&ee->element_hash,
@@ -1429,7 +1496,6 @@ handle_p2p_elements (void *cls,
{
/* We got something we didn't demand, since it's not in our map. */
GNUNET_break_op (0);
- GNUNET_free (ee);
fail_union_operation (op);
return;
}
@@ -1448,10 +1514,9 @@ handle_p2p_elements (void *cls,
1,
GNUNET_NO);
- op->state->received_total += 1;
-
- struct KeyEntry *ke = op_get_element (op, &ee->element_hash);
+ op->state->received_total++;
+ ke = op_get_element (op, &ee->element_hash);
if (NULL != ke)
{
/* Got repeated element. Should not happen since
@@ -1467,7 +1532,7 @@ handle_p2p_elements (void *cls,
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Registering new element from remote peer\n");
- op->state->received_fresh += 1;
+ op->state->received_fresh++;
op_register_element (op, ee, GNUNET_YES);
/* only send results immediately if the client wants it */
switch (op->spec->result_mode)
@@ -1485,43 +1550,57 @@ handle_p2p_elements (void *cls,
}
}
- if (op->state->received_total > 8 && op->state->received_fresh < op->state->received_total / 3)
+ if ( (op->state->received_total > 8) &&
+ (op->state->received_fresh < op->state->received_total / 3) )
{
/* The other peer gave us lots of old elements, there's something wrong. */
GNUNET_break_op (0);
fail_union_operation (op);
return;
}
-
+ GNUNET_CADET_receive_done (op->channel);
maybe_finish (op);
}
/**
- * Handle an element message from a remote peer.
+ * Check a full element message from a remote peer.
*
* @param cls the union operation
- * @param mh the message
+ * @param emsg the message
*/
-static void
-handle_p2p_full_element (void *cls,
- const struct GNUNET_MessageHeader *mh)
+int
+check_union_p2p_full_element (void *cls,
+ const struct GNUNET_SET_ElementMessage *emsg)
{
struct Operation *op = cls;
- struct ElementEntry *ee;
- const struct GNUNET_SET_ElementMessage *emsg;
- uint16_t element_size;
- if (ntohs (mh->size) < sizeof (struct GNUNET_SET_ElementMessage))
+ if (OT_UNION != op->type)
{
GNUNET_break_op (0);
- fail_union_operation (op);
- return;
+ return GNUNET_SYSERR;
}
+ // FIXME: check that we expect full elements here?
+ return GNUNET_OK;
+}
- emsg = (const struct GNUNET_SET_ElementMessage *) mh;
- element_size = ntohs (mh->size) - sizeof (struct GNUNET_SET_ElementMessage);
+/**
+ * Handle an element message from a remote peer.
+ *
+ * @param cls the union operation
+ * @param emsg the message
+ */
+void
+handle_union_p2p_full_element (void *cls,
+ const struct GNUNET_SET_ElementMessage *emsg)
+{
+ struct Operation *op = cls;
+ struct ElementEntry *ee;
+ struct KeyEntry *ke;
+ uint16_t element_size;
+
+ element_size = ntohs (emsg->header.size) - sizeof (struct GNUNET_SET_ElementMessage);
ee = GNUNET_malloc (sizeof (struct ElementEntry) + element_size);
GNUNET_memcpy (&ee[1], &emsg[1], element_size);
ee->element.size = element_size;
@@ -1544,10 +1623,9 @@ handle_p2p_full_element (void *cls,
1,
GNUNET_NO);
- op->state->received_total += 1;
-
- struct KeyEntry *ke = op_get_element (op, &ee->element_hash);
+ op->state->received_total++;
+ ke = op_get_element (op, &ee->element_hash);
if (NULL != ke)
{
/* Got repeated element. Should not happen since
@@ -1563,7 +1641,7 @@ handle_p2p_full_element (void *cls,
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Registering new element from remote peer\n");
- op->state->received_fresh += 1;
+ op->state->received_fresh++;
op_register_element (op, ee, GNUNET_YES);
/* only send results immediately if the client wants it */
switch (op->spec->result_mode)
@@ -1581,8 +1659,8 @@ handle_p2p_full_element (void *cls,
}
}
- if ( (GNUNET_YES == op->spec->byzantine) &&
- (op->state->received_total > 384 + op->state->received_fresh * 4) &&
+ if ( (GNUNET_YES == op->spec->byzantine) &&
+ (op->state->received_total > 384 + op->state->received_fresh * 4) &&
(op->state->received_fresh < op->state->received_total / 6) )
{
/* The other peer gave us lots of old elements, there's something wrong. */
@@ -1594,51 +1672,73 @@ handle_p2p_full_element (void *cls,
fail_union_operation (op);
return;
}
+ GNUNET_CADET_receive_done (op->channel);
}
+
/**
* Send offers (for GNUNET_Hash-es) in response
* to inquiries (for IBF_Key-s).
*
* @param cls the union operation
- * @param mh the message
+ * @param msg the message
*/
-static void
-handle_p2p_inquiry (void *cls,
- const struct GNUNET_MessageHeader *mh)
+int
+check_union_p2p_inquiry (void *cls,
+ const struct InquiryMessage *msg)
{
struct Operation *op = cls;
- const struct IBF_Key *ibf_key;
unsigned int num_keys;
- struct InquiryMessage *msg;
- /* look up elements and send them */
+ if (OT_UNION != op->type)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
if (op->state->phase != PHASE_INVENTORY_PASSIVE)
{
GNUNET_break_op (0);
- fail_union_operation (op);
- return;
+ return GNUNET_SYSERR;
}
- num_keys = (ntohs (mh->size) - sizeof (struct InquiryMessage))
- / sizeof (struct IBF_Key);
- if ((ntohs (mh->size) - sizeof (struct InquiryMessage))
+ num_keys = (ntohs (msg->header.size) - sizeof (struct InquiryMessage))
+ / sizeof (struct IBF_Key);
+ if ((ntohs (msg->header.size) - sizeof (struct InquiryMessage))
!= num_keys * sizeof (struct IBF_Key))
{
GNUNET_break_op (0);
- fail_union_operation (op);
- return;
+ return GNUNET_SYSERR;
}
+ return GNUNET_OK;
+}
+
- msg = (struct InquiryMessage *) mh;
+/**
+ * Send offers (for GNUNET_Hash-es) in response
+ * to inquiries (for IBF_Key-s).
+ *
+ * @param cls the union operation
+ * @param msg the message
+ */
+void
+handle_union_p2p_inquiry (void *cls,
+ const struct InquiryMessage *msg)
+{
+ struct Operation *op = cls;
+ const struct IBF_Key *ibf_key;
+ unsigned int num_keys;
+ num_keys = (ntohs (msg->header.size) - sizeof (struct InquiryMessage))
+ / sizeof (struct IBF_Key);
ibf_key = (const struct IBF_Key *) &msg[1];
while (0 != num_keys--)
{
struct IBF_Key unsalted_key;
+
unsalt_key (ibf_key, ntohl (msg->salt), &unsalted_key);
send_offers_for_key (op, unsalted_key);
ibf_key++;
}
+ GNUNET_CADET_receive_done (op->channel);
}
@@ -1677,27 +1777,36 @@ send_missing_elements_iter (void *cls,
/**
- * Handle a
+ * Handle a request for full set transmission.
*
* @parem cls closure, a set union operation
* @param mh the demand message
*/
-static void
-handle_p2p_request_full (void *cls,
- const struct GNUNET_MessageHeader *mh)
+void
+handle_union_p2p_request_full (void *cls,
+ const struct GNUNET_MessageHeader *mh)
{
struct Operation *op = cls;
- if (PHASE_EXPECT_IBF != op->state->phase)
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Received request for full set transmission\n");
+ if (OT_UNION != op->type)
{
+ GNUNET_break_op (0);
fail_union_operation (op);
+ return;
+ }
+ if (PHASE_EXPECT_IBF != op->state->phase)
+ {
GNUNET_break_op (0);
+ fail_union_operation (op);
return;
}
// FIXME: we need to check that our set is larger than the
// byzantine_lower_bound by some threshold
send_full_set (op);
+ GNUNET_CADET_receive_done (op->channel);
}
@@ -1707,56 +1816,97 @@ handle_p2p_request_full (void *cls,
* @parem cls closure, a set union operation
* @param mh the demand message
*/
-static void
-handle_p2p_full_done (void *cls,
- const struct GNUNET_MessageHeader *mh)
+void
+handle_union_p2p_full_done (void *cls,
+ const struct GNUNET_MessageHeader *mh)
{
struct Operation *op = cls;
- if (PHASE_EXPECT_IBF == op->state->phase)
+ switch (op->state->phase)
{
- struct GNUNET_MQ_Envelope *ev;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "got FULL DONE, sending elements that other peer is missing\n");
+ case PHASE_EXPECT_IBF:
+ {
+ struct GNUNET_MQ_Envelope *ev;
- /* send all the elements that did not come from the remote peer */
- GNUNET_CONTAINER_multihashmap32_iterate (op->state->key_to_element,
- &send_missing_elements_iter,
- op);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "got FULL DONE, sending elements that other peer is missing\n");
- ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE);
- GNUNET_MQ_send (op->mq, ev);
- op->state->phase = PHASE_DONE;
+ /* send all the elements that did not come from the remote peer */
+ GNUNET_CONTAINER_multihashmap32_iterate (op->state->key_to_element,
+ &send_missing_elements_iter,
+ op);
- /* we now wait until the other peer shuts the tunnel down*/
+ ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE);
+ GNUNET_MQ_send (op->mq, ev);
+ op->state->phase = PHASE_DONE;
+ /* we now wait until the other peer shuts the tunnel down*/
+ }
+ break;
+ case PHASE_FULL_SENDING:
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "got FULL DONE, finishing\n");
+ /* We sent the full set, and got the response for that. We're done. */
+ op->state->phase = PHASE_DONE;
+ GNUNET_CADET_receive_done (op->channel);
+ send_done_and_destroy (op);
+ return;
+ }
+ break;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Handle full done phase is %u\n",
+ (unsigned) op->state->phase);
+ GNUNET_break_op (0);
+ fail_union_operation (op);
+ return;
}
- else if (PHASE_FULL_SENDING == op->state->phase)
+ GNUNET_CADET_receive_done (op->channel);
+}
+
+
+/**
+ * Check a demand by the other peer for elements based on a list
+ * of `struct GNUNET_HashCode`s.
+ *
+ * @parem cls closure, a set union operation
+ * @param mh the demand message
+ * @return #GNUNET_OK if @a mh is well-formed
+ */
+int
+check_union_p2p_demand (void *cls,
+ const struct GNUNET_MessageHeader *mh)
+{
+ struct Operation *op = cls;
+ unsigned int num_hashes;
+
+ if (OT_UNION != op->type)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "got FULL DONE, finishing\n");
- /* We sent the full set, and got the response for that. We're done. */
- op->state->phase = PHASE_DONE;
- send_done_and_destroy (op);
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
}
- else
+ num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
+ / sizeof (struct GNUNET_HashCode);
+ if ((ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
+ != num_hashes * sizeof (struct GNUNET_HashCode))
{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "handle full done phase is %u\n", (unsigned) op->state->phase);
GNUNET_break_op (0);
- fail_union_operation (op);
- return;
+ return GNUNET_SYSERR;
}
+ return GNUNET_OK;
}
/**
* Handle a demand by the other peer for elements based on a list
- * of GNUNET_HashCode-s.
+ * of `struct GNUNET_HashCode`s.
*
* @parem cls closure, a set union operation
* @param mh the demand message
*/
-static void
-handle_p2p_demand (void *cls,
- const struct GNUNET_MessageHeader *mh)
+void
+handle_union_p2p_demand (void *cls,
+ const struct GNUNET_MessageHeader *mh)
{
struct Operation *op = cls;
struct ElementEntry *ee;
@@ -1767,19 +1917,12 @@ handle_p2p_demand (void *cls,
num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
/ sizeof (struct GNUNET_HashCode);
- if ((ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
- != num_hashes * sizeof (struct GNUNET_HashCode))
- {
- GNUNET_break_op (0);
- fail_union_operation (op);
- return;
- }
-
for (hash = (const struct GNUNET_HashCode *) &mh[1];
num_hashes > 0;
hash++, num_hashes--)
{
- ee = GNUNET_CONTAINER_multihashmap_get (op->spec->set->content->elements, hash);
+ ee = GNUNET_CONTAINER_multihashmap_get (op->spec->set->content->elements,
+ hash);
if (NULL == ee)
{
/* Demand for non-existing element. */
@@ -1823,31 +1966,35 @@ handle_p2p_demand (void *cls,
break;
}
}
+ GNUNET_CADET_receive_done (op->channel);
}
/**
- * Handle offers (of GNUNET_HashCode-s) and
- * respond with demands (of GNUNET_HashCode-s).
+ * Check offer (of `struct GNUNET_HashCode`s).
*
* @param cls the union operation
* @param mh the message
+ * @return #GNUNET_OK if @a mh is well-formed
*/
-static void
-handle_p2p_offer (void *cls,
- const struct GNUNET_MessageHeader *mh)
+int
+check_union_p2p_offer (void *cls,
+ const struct GNUNET_MessageHeader *mh)
{
struct Operation *op = cls;
- const struct GNUNET_HashCode *hash;
unsigned int num_hashes;
+ if (OT_UNION != op->type)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
/* look up elements and send them */
if ( (op->state->phase != PHASE_INVENTORY_PASSIVE) &&
(op->state->phase != PHASE_INVENTORY_ACTIVE))
{
GNUNET_break_op (0);
- fail_union_operation (op);
- return;
+ return GNUNET_SYSERR;
}
num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
/ sizeof (struct GNUNET_HashCode);
@@ -1855,10 +2002,29 @@ handle_p2p_offer (void *cls,
!= num_hashes * sizeof (struct GNUNET_HashCode))
{
GNUNET_break_op (0);
- fail_union_operation (op);
- return;
+ return GNUNET_SYSERR;
}
+ return GNUNET_OK;
+}
+
+
+/**
+ * Handle offers (of `struct GNUNET_HashCode`s) and
+ * respond with demands (of `struct GNUNET_HashCode`s).
+ *
+ * @param cls the union operation
+ * @param mh the message
+ */
+void
+handle_union_p2p_offer (void *cls,
+ const struct GNUNET_MessageHeader *mh)
+{
+ struct Operation *op = cls;
+ const struct GNUNET_HashCode *hash;
+ unsigned int num_hashes;
+ num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
+ / sizeof (struct GNUNET_HashCode);
for (hash = (const struct GNUNET_HashCode *) &mh[1];
num_hashes > 0;
hash++, num_hashes--)
@@ -1897,6 +2063,7 @@ handle_p2p_offer (void *cls,
*(struct GNUNET_HashCode *) &demands[1] = *hash;
GNUNET_MQ_send (op->mq, ev);
}
+ GNUNET_CADET_receive_done (op->channel);
}
@@ -1906,16 +2073,22 @@ handle_p2p_offer (void *cls,
* @param cls the union operation
* @param mh the message
*/
-static void
-handle_p2p_done (void *cls,
- const struct GNUNET_MessageHeader *mh)
+void
+handle_union_p2p_done (void *cls,
+ const struct GNUNET_MessageHeader *mh)
{
struct Operation *op = cls;
- if (op->state->phase == PHASE_INVENTORY_PASSIVE)
+ if (OT_UNION != op->type)
{
+ GNUNET_break_op (0);
+ fail_union_operation (op);
+ return;
+ }
+ switch (op->state->phase)
+ {
+ case PHASE_INVENTORY_PASSIVE:
/* We got all requests, but still have to send our elements in response. */
-
op->state->phase = PHASE_FINISH_WAITING;
LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -1929,11 +2102,10 @@ handle_p2p_done (void *cls,
* all our demands are satisfied, so that the active
* peer can quit if we gave him everything.
*/
+ GNUNET_CADET_receive_done (op->channel);
maybe_finish (op);
return;
- }
- if (op->state->phase == PHASE_INVENTORY_ACTIVE)
- {
+ case PHASE_INVENTORY_ACTIVE:
LOG (GNUNET_ERROR_TYPE_DEBUG,
"got DONE (as active partner), waiting to finish\n");
/* All demands of the other peer are satisfied,
@@ -1944,11 +2116,14 @@ handle_p2p_done (void *cls,
* to the other peer once our demands are met.
*/
op->state->phase = PHASE_FINISH_CLOSING;
+ GNUNET_CADET_receive_done (op->channel);
maybe_finish (op);
return;
+ default:
+ GNUNET_break_op (0);
+ fail_union_operation (op);
+ return;
}
- GNUNET_break_op (0);
- fail_union_operation (op);
}
@@ -2119,62 +2294,6 @@ union_set_destroy (struct SetState *set_state)
/**
- * Dispatch messages for a union operation.
- *
- * @param op the state of the union evaluate operation
- * @param mh the received message
- * @return #GNUNET_SYSERR if the tunnel should be disconnected,
- * #GNUNET_OK otherwise
- */
-int
-union_handle_p2p_message (struct Operation *op,
- const struct GNUNET_MessageHeader *mh)
-{
- //LOG (GNUNET_ERROR_TYPE_DEBUG,
- // "received p2p message (t: %u, s: %u)\n",
- // ntohs (mh->type),
- // ntohs (mh->size));
- switch (ntohs (mh->type))
- {
- case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF:
- return handle_p2p_ibf (op, mh);
- case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE:
- return handle_p2p_strata_estimator (op, mh, GNUNET_NO);
- case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC:
- return handle_p2p_strata_estimator (op, mh, GNUNET_YES);
- case GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS:
- handle_p2p_elements (op, mh);
- break;
- case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT:
- handle_p2p_full_element (op, mh);
- break;
- case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY:
- handle_p2p_inquiry (op, mh);
- break;
- case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE:
- handle_p2p_done (op, mh);
- break;
- case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER:
- handle_p2p_offer (op, mh);
- break;
- case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND:
- handle_p2p_demand (op, mh);
- break;
- case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE:
- handle_p2p_full_done (op, mh);
- break;
- case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL:
- handle_p2p_request_full (op, mh);
- break;
- default:
- /* Something wrong with cadet's message handlers? */
- GNUNET_assert (0);
- }
- return GNUNET_OK;
-}
-
-
-/**
* Handler for peer-disconnects, notifies the client
* about the aborted operation in case the op was not concluded.
*
@@ -2240,7 +2359,6 @@ _GSS_union_vt ()
{
static const struct SetVT union_vt = {
.create = &union_set_create,
- .msg_handler = &union_handle_p2p_message,
.add = &union_add,
.remove = &union_remove,
.destroy_set = &union_set_destroy,
diff --git a/src/set/set_api.c b/src/set/set_api.c
index 04a4e49108..bc428f9f6d 100644
--- a/src/set/set_api.c
+++ b/src/set/set_api.c
@@ -76,6 +76,8 @@ struct GNUNET_SET_Handle
/**
* Should the set be destroyed once all operations are gone?
+ * #GNUNET_SYSERR if #GNUNET_SET_destroy() must raise this flag,
+ * #GNUNET_YES if #GNUNET_SET_destroy() did raise this flag.
*/
int destroy_requested;
@@ -345,11 +347,13 @@ handle_iter_done (void *cls,
if (NULL == iter)
return;
+ set->destroy_requested = GNUNET_SYSERR;
set->iterator = NULL;
set->iteration_id++;
iter (set->iterator_cls,
NULL);
-
+ if (GNUNET_SYSERR == set->destroy_requested)
+ set->destroy_requested = GNUNET_NO;
if (GNUNET_YES == set->destroy_requested)
GNUNET_SET_destroy (set);
}
@@ -736,7 +740,9 @@ GNUNET_SET_destroy (struct GNUNET_SET_Handle *set)
/* destroying set while iterator is active is currently
not supported; we should expand the API to allow
clients to explicitly cancel the iteration! */
- if ( (NULL != set->ops_head) || (NULL != set->iterator) )
+ if ( (NULL != set->ops_head) ||
+ (NULL != set->iterator) ||
+ (GNUNET_SYSERR == set->destroy_requested) )
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Set operations are pending, delaying set destruction\n");
@@ -809,7 +815,7 @@ GNUNET_SET_prepare (const struct GNUNET_PeerIdentity *other_peer,
msg->force_delta = GNUNET_YES;
break;
default:
- LOG (GNUNET_ERROR_TYPE_ERROR,
+ LOG (GNUNET_ERROR_TYPE_ERROR,
"Option with type %d not recognized\n", (int) opt->type);
}
}
diff --git a/src/set/test_set_union_copy.c b/src/set/test_set_union_copy.c
index c887a89588..a1eba63115 100644
--- a/src/set/test_set_union_copy.c
+++ b/src/set/test_set_union_copy.c
@@ -122,6 +122,7 @@ check_count_iter (void *cls,
return GNUNET_NO;
}
ci_cls->cont (ci_cls->cont_cls);
+ GNUNET_free (ci_cls);
return GNUNET_NO;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
diff --git a/src/sq/sq.c b/src/sq/sq.c
index 114de2d88f..089ebf0ffc 100644
--- a/src/sq/sq.c
+++ b/src/sq/sq.c
@@ -90,7 +90,12 @@ GNUNET_SQ_extract_result (sqlite3_stmt *result,
j,
rs[i].result_size,
rs[i].dst))
+ {
+ for (unsigned int k=0;k<i;k++)
+ if (NULL != rs[k].cleaner)
+ rs[k].cleaner (rs[k].cls);
return GNUNET_SYSERR;
+ }
GNUNET_assert (0 != rs[i].num_params);
j += rs[i].num_params;
}
@@ -112,4 +117,24 @@ GNUNET_SQ_cleanup_result (struct GNUNET_SQ_ResultSpec *rs)
rs[i].cleaner (rs[i].cls);
}
+
+/**
+ * Reset @a stmt and log error.
+ *
+ * @param dbh database handle
+ * @param stmt statement to reset
+ */
+void
+GNUNET_SQ_reset (sqlite3 *dbh,
+ sqlite3_stmt *stmt)
+{
+ if (SQLITE_OK !=
+ sqlite3_reset (stmt))
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ "sqlite",
+ _("Failed to reset sqlite statement with error: %s\n"),
+ sqlite3_errmsg (dbh));
+}
+
+
/* end of sq.c */
diff --git a/src/sq/sq_query_helper.c b/src/sq/sq_query_helper.c
index 5529c5e6c2..a04b4ced45 100644
--- a/src/sq/sq_query_helper.c
+++ b/src/sq/sq_query_helper.c
@@ -235,6 +235,40 @@ GNUNET_SQ_query_param_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *x)
/**
+ * Function called to convert input argument into SQL parameters.
+ *
+ * @param cls closure
+ * @param data pointer to input argument
+ * @param data_len number of bytes in @a data (if applicable)
+ * @param stmt sqlite statement to bind parameters for
+ * @param off offset of the argument to bind in @a stmt, numbered from 1,
+ * so immediately suitable for passing to `sqlite3_bind`-functions.
+ * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
+ */
+static int
+bind_abstime (void *cls,
+ const void *data,
+ size_t data_len,
+ sqlite3_stmt *stmt,
+ unsigned int off)
+{
+ const struct GNUNET_TIME_Absolute *u = data;
+ struct GNUNET_TIME_Absolute abs;
+
+ abs = *u;
+ if (abs.abs_value_us > INT64_MAX)
+ abs.abs_value_us = INT64_MAX;
+ GNUNET_assert (sizeof (uint64_t) == data_len);
+ if (SQLITE_OK !=
+ sqlite3_bind_int64 (stmt,
+ (int) off,
+ (sqlite3_int64) abs.abs_value_us))
+ return GNUNET_SYSERR;
+ return GNUNET_OK;
+}
+
+
+/**
* Generate query parameter for an absolute time value.
* The database must store a 64-bit integer.
*
@@ -243,7 +277,13 @@ GNUNET_SQ_query_param_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *x)
struct GNUNET_SQ_QueryParam
GNUNET_SQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x)
{
- return GNUNET_SQ_query_param_uint64 (&x->abs_value_us);
+ struct GNUNET_SQ_QueryParam qp = {
+ .conv = &bind_abstime,
+ .data = x,
+ .size = sizeof (struct GNUNET_TIME_Absolute),
+ .num_params = 1
+ };
+ return qp;
}
@@ -269,6 +309,8 @@ bind_nbotime (void *cls,
struct GNUNET_TIME_Absolute abs;
abs = GNUNET_TIME_absolute_ntoh (*u);
+ if (abs.abs_value_us > INT64_MAX)
+ abs.abs_value_us = INT64_MAX;
GNUNET_assert (sizeof (uint64_t) == data_len);
if (SQLITE_OK !=
sqlite3_bind_int64 (stmt,
diff --git a/src/sq/sq_result_helper.c b/src/sq/sq_result_helper.c
index eaf606aa44..fad3f3c8d4 100644
--- a/src/sq/sq_result_helper.c
+++ b/src/sq/sq_result_helper.c
@@ -46,6 +46,15 @@ extract_var_blob (void *cls,
const void *ret;
void **rdst = (void **) dst;
+ if (SQLITE_NULL ==
+ sqlite3_column_type (result,
+ column))
+ {
+ *rdst = NULL;
+ *dst_size = 0;
+ return GNUNET_YES;
+ }
+
if (SQLITE_BLOB !=
sqlite3_column_type (result,
column))
@@ -142,6 +151,14 @@ extract_fixed_blob (void *cls,
int have;
const void *ret;
+ if ( (0 == *dst_size) &&
+ (SQLITE_NULL ==
+ sqlite3_column_type (result,
+ column)) )
+ {
+ return GNUNET_YES;
+ }
+
if (SQLITE_BLOB !=
sqlite3_column_type (result,
column))
@@ -459,6 +476,45 @@ GNUNET_SQ_result_spec_rsa_signature (struct GNUNET_CRYPTO_RsaSignature **sig)
/**
+ * Extract absolute time value from a Postgres database @a result at row @a row.
+ *
+ * @param cls closure
+ * @param result where to extract data from
+ * @param column column to extract data from
+ * @param[in,out] dst_size where to store size of result, may be NULL
+ * @param[out] dst where to store the result
+ * @return
+ * #GNUNET_YES if all results could be extracted
+ * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
+ */
+static int
+extract_abs_time (void *cls,
+ sqlite3_stmt *result,
+ unsigned int column,
+ size_t *dst_size,
+ void *dst)
+{
+ struct GNUNET_TIME_Absolute *u = dst;
+ struct GNUNET_TIME_Absolute t;
+
+ GNUNET_assert (sizeof (uint64_t) == *dst_size);
+ if (SQLITE_INTEGER !=
+ sqlite3_column_type (result,
+ column))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ t.abs_value_us = (uint64_t) sqlite3_column_int64 (result,
+ column);
+ if (INT64_MAX == t.abs_value_us)
+ t = GNUNET_TIME_UNIT_FOREVER_ABS;
+ *u = t;
+ return GNUNET_OK;
+}
+
+
+/**
* Absolute time expected.
*
* @param[out] at where to store the result
@@ -467,7 +523,14 @@ GNUNET_SQ_result_spec_rsa_signature (struct GNUNET_CRYPTO_RsaSignature **sig)
struct GNUNET_SQ_ResultSpec
GNUNET_SQ_result_spec_absolute_time (struct GNUNET_TIME_Absolute *at)
{
- return GNUNET_SQ_result_spec_uint64 (&at->abs_value_us);
+ struct GNUNET_SQ_ResultSpec rs = {
+ .conv = &extract_abs_time,
+ .dst = at,
+ .dst_size = sizeof (struct GNUNET_TIME_Absolute),
+ .num_params = 1
+ };
+
+ return rs;
}
@@ -503,6 +566,8 @@ extract_abs_time_nbo (void *cls,
}
t.abs_value_us = (uint64_t) sqlite3_column_int64 (result,
column);
+ if (INT64_MAX == t.abs_value_us)
+ t = GNUNET_TIME_UNIT_FOREVER_ABS;
*u = GNUNET_TIME_absolute_hton (t);
return GNUNET_OK;
}