[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r33186 - in gnunet/src: . cadet mesh
From: |
gnunet |
Subject: |
[GNUnet-SVN] r33186 - in gnunet/src: . cadet mesh |
Date: |
Wed, 7 May 2014 14:07:16 +0200 |
Author: bartpolot
Date: 2014-05-07 14:07:16 +0200 (Wed, 07 May 2014)
New Revision: 33186
Added:
gnunet/src/cadet/
gnunet/src/cadet/Makefile.am
gnunet/src/cadet/beautify_log.sh
gnunet/src/cadet/cadet.h
gnunet/src/cadet/cadet_api.c
gnunet/src/cadet/cadet_common.c
gnunet/src/cadet/cadet_path.c
gnunet/src/cadet/cadet_path.h
gnunet/src/cadet/cadet_protocol.h
gnunet/src/cadet/cadet_test_lib.c
gnunet/src/cadet/cadet_test_lib.h
gnunet/src/cadet/cadet_tunnel_tree.c
gnunet/src/cadet/cadet_tunnel_tree.h
gnunet/src/cadet/gnunet-cadet-profiler.c
gnunet/src/cadet/gnunet-cadet.c
gnunet/src/cadet/gnunet-service-cadet.c
gnunet/src/cadet/gnunet-service-cadet_channel.c
gnunet/src/cadet/gnunet-service-cadet_channel.h
gnunet/src/cadet/gnunet-service-cadet_connection.c
gnunet/src/cadet/gnunet-service-cadet_connection.h
gnunet/src/cadet/gnunet-service-cadet_dht.c
gnunet/src/cadet/gnunet-service-cadet_dht.h
gnunet/src/cadet/gnunet-service-cadet_hello.c
gnunet/src/cadet/gnunet-service-cadet_hello.h
gnunet/src/cadet/gnunet-service-cadet_local.c
gnunet/src/cadet/gnunet-service-cadet_local.h
gnunet/src/cadet/gnunet-service-cadet_peer.c
gnunet/src/cadet/gnunet-service-cadet_peer.h
gnunet/src/cadet/gnunet-service-cadet_tunnel.c
gnunet/src/cadet/gnunet-service-cadet_tunnel.h
gnunet/src/cadet/loopcheck.sh
gnunet/src/cadet/mesh.conf.in
gnunet/src/cadet/profiler.conf
gnunet/src/cadet/run_profiler.sh
gnunet/src/cadet/small.dat
gnunet/src/cadet/test_cadet.c
gnunet/src/cadet/test_cadet.conf
gnunet/src/cadet/test_cadet_drop.conf
gnunet/src/cadet/test_cadet_local.c
gnunet/src/cadet/test_cadet_single.c
gnunet/src/cadet/valgrind-mesh.supp
Removed:
gnunet/src/mesh/Makefile.am
gnunet/src/mesh/beautify_log.sh
gnunet/src/mesh/cadet.h
gnunet/src/mesh/cadet_api.c
gnunet/src/mesh/cadet_common.c
gnunet/src/mesh/cadet_path.c
gnunet/src/mesh/cadet_path.h
gnunet/src/mesh/cadet_protocol.h
gnunet/src/mesh/cadet_test_lib.c
gnunet/src/mesh/cadet_test_lib.h
gnunet/src/mesh/cadet_tunnel_tree.c
gnunet/src/mesh/cadet_tunnel_tree.h
gnunet/src/mesh/gnunet-cadet-profiler.c
gnunet/src/mesh/gnunet-cadet.c
gnunet/src/mesh/gnunet-service-cadet.c
gnunet/src/mesh/gnunet-service-cadet_channel.c
gnunet/src/mesh/gnunet-service-cadet_channel.h
gnunet/src/mesh/gnunet-service-cadet_connection.c
gnunet/src/mesh/gnunet-service-cadet_connection.h
gnunet/src/mesh/gnunet-service-cadet_dht.c
gnunet/src/mesh/gnunet-service-cadet_dht.h
gnunet/src/mesh/gnunet-service-cadet_hello.c
gnunet/src/mesh/gnunet-service-cadet_hello.h
gnunet/src/mesh/gnunet-service-cadet_local.c
gnunet/src/mesh/gnunet-service-cadet_local.h
gnunet/src/mesh/gnunet-service-cadet_peer.c
gnunet/src/mesh/gnunet-service-cadet_peer.h
gnunet/src/mesh/gnunet-service-cadet_tunnel.c
gnunet/src/mesh/gnunet-service-cadet_tunnel.h
gnunet/src/mesh/loopcheck.sh
gnunet/src/mesh/mesh.conf.in
gnunet/src/mesh/profiler.conf
gnunet/src/mesh/run_profiler.sh
gnunet/src/mesh/small.dat
gnunet/src/mesh/test_cadet.c
gnunet/src/mesh/test_cadet.conf
gnunet/src/mesh/test_cadet_drop.conf
gnunet/src/mesh/test_cadet_local.c
gnunet/src/mesh/test_cadet_single.c
gnunet/src/mesh/valgrind-mesh.supp
Log:
Renamed directory
Copied: gnunet/src/cadet/Makefile.am (from rev 33185,
gnunet/src/mesh/Makefile.am)
===================================================================
--- gnunet/src/cadet/Makefile.am (rev 0)
+++ gnunet/src/cadet/Makefile.am 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,194 @@
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+if MINGW
+ WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
+endif
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage -O0
+ XLIB = -lgcov
+endif
+
+pkgcfgdir= $(pkgdatadir)/config.d/
+
+libexecdir= $(pkglibdir)/libexec/
+
+pkgcfg_DATA = \
+ cadet.conf
+
+plugindir = $(libdir)/gnunet
+
+AM_CLFAGS = -g
+
+libexec_PROGRAMS = \
+ gnunet-service-cadet $(EXP_LIBEXEC)
+
+bin_PROGRAMS = \
+ gnunet-cadet
+
+lib_LTLIBRARIES = \
+ libgnunetcadet.la $(EXP_LIB)
+
+libgnunetcadet_la_SOURCES = \
+ cadet_api.c cadet_common.c
+libgnunetcadet_la_LIBADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(XLIB) \
+ $(LTLIBINTL)
+libgnunetcadet_la_LDFLAGS = \
+ $(GN_LIB_LDFLAGS) $(WINFLAGS) \
+ -version-info 5:0:0
+
+gnunet_cadet_SOURCES = \
+ gnunet-cadet.c
+gnunet_cadet_LDADD = \
+ $(top_builddir)/src/cadet/libgnunetcadet.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+gnunet_cadet_DEPENDENCIES = \
+ libgnunetcadet.la
+
+gnunet_service_cadet_SOURCES = \
+ gnunet-service-cadet_tunnel.c gnunet-service-cadet_tunnel.h \
+ gnunet-service-cadet_connection.c gnunet-service-cadet_connection.h \
+ gnunet-service-cadet_channel.c gnunet-service-cadet_channel.h \
+ gnunet-service-cadet_local.c gnunet-service-cadet_local.h \
+ gnunet-service-cadet_peer.c gnunet-service-cadet_peer.h \
+ gnunet-service-cadet_dht.c gnunet-service-cadet_dht.h \
+ gnunet-service-cadet_hello.c gnunet-service-cadet_hello.h \
+ cadet_path.c cadet_path.h \
+ cadet_common.c \
+ gnunet-service-cadet.c
+gnunet_service_cadet_CFLAGS = $(AM_CFLAGS)
+gnunet_service_cadet_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/core/libgnunetcore.la \
+ $(top_builddir)/src/dht/libgnunetdht.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/block/libgnunetblock.la
+gnunet_service_cadet_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/core/libgnunetcore.la \
+ $(top_builddir)/src/dht/libgnunetdht.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/block/libgnunetblock.la
+if LINUX
+ gnunet_service_cadet_LDFLAGS = -lrt
+endif
+
+
+if HAVE_TESTING
+ noinst_LIBRARIES = libgnunetcadettest.a $(noinst_LIB_EXP)
+ noinst_PROGRAMS = gnunet-cadet-profiler
+endif
+
+libgnunetcadettest_a_SOURCES = \
+ cadet_test_lib.c cadet_test_lib.h
+libgnunetcadettest_a_LIBADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testbed/libgnunettestbed.la \
+ $(top_builddir)/src/cadet/libgnunetcadet.la
+libgnunetcadettest_a_DEPENDENCIES = \
+ libgnunetcadet.la
+
+if HAVE_TESTING
+check_PROGRAMS = \
+ test_cadet_single \
+ test_cadet_local \
+ test_cadet_forward \
+ test_cadet_signal \
+ test_cadet_keepalive \
+ test_cadet_speed \
+ test_cadet_speed_ack \
+ test_cadet_speed_backwards \
+ test_cadet_speed_reliable \
+ test_cadet_speed_reliable_backwards
+endif
+
+ld_cadet_test_lib = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ $(top_builddir)/src/cadet/libgnunetcadettest.a \
+ $(top_builddir)/src/cadet/libgnunetcadet.la \
+ $(top_builddir)/src/testbed/libgnunettestbed.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la
+
+dep_cadet_test_lib = \
+ libgnunetcadet.la \
+ libgnunetcadettest.a \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la
+
+
+gnunet_cadet_profiler_SOURCES = \
+ gnunet-cadet-profiler.c
+gnunet_cadet_profiler_LDADD = $(ld_cadet_test_lib)
+gnunet_cadet_profiler_DEPENDENCIES = $(dep_cadet_test_lib)
+
+
+test_cadet_single_SOURCES = \
+ test_cadet_single.c
+test_cadet_single_LDADD = $(ld_cadet_test_lib)
+test_cadet_single_DEPENDENCIES = $(dep_cadet_test_lib)
+
+test_cadet_local_SOURCES = \
+ test_cadet_local.c
+test_cadet_local_LDADD = $(ld_cadet_test_lib)
+test_cadet_local_DEPENDENCIES = $(dep_cadet_test_lib)
+
+test_cadet_forward_SOURCES = \
+ test_cadet.c
+test_cadet_forward_LDADD = $(ld_cadet_test_lib)
+test_cadet_forward_DEPENDENCIES = $(dep_cadet_test_lib)
+
+test_cadet_signal_SOURCES = \
+ test_cadet.c
+test_cadet_signal_LDADD = $(ld_cadet_test_lib)
+test_cadet_signal_DEPENDENCIES = $(dep_cadet_test_lib)
+
+test_cadet_keepalive_SOURCES = \
+ test_cadet.c
+test_cadet_keepalive_LDADD = $(ld_cadet_test_lib)
+test_cadet_keepalive_DEPENDENCIES = $(dep_cadet_test_lib)
+
+test_cadet_speed_SOURCES = \
+ test_cadet.c
+test_cadet_speed_LDADD = $(ld_cadet_test_lib)
+test_cadet_speed_DEPENDENCIES = $(dep_cadet_test_lib)
+
+test_cadet_speed_ack_SOURCES = \
+ test_cadet.c
+test_cadet_speed_ack_LDADD = $(ld_cadet_test_lib)
+test_cadet_speed_ack_DEPENDENCIES = $(dep_cadet_test_lib)
+
+test_cadet_speed_backwards_SOURCES = \
+ test_cadet.c
+test_cadet_speed_backwards_LDADD = $(ld_cadet_test_lib)
+test_cadet_speed_backwards_DEPENDENCIES = $(dep_cadet_test_lib)
+
+test_cadet_speed_reliable_SOURCES = \
+ test_cadet.c
+test_cadet_speed_reliable_LDADD = $(ld_cadet_test_lib)
+test_cadet_speed_reliable_DEPENDENCIES = $(dep_cadet_test_lib)
+
+test_cadet_speed_reliable_backwards_SOURCES = \
+ test_cadet.c
+test_cadet_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib)
+test_cadet_speed_reliable_backwards_DEPENDENCIES = $(dep_cadet_test_lib)
+
+
+if ENABLE_TEST_RUN
+AM_TESTS_ENVIRONMENT=export
GNUNET_PREFIX=$${GNUNET_PREFIX:address@hidden@};export
PATH=$${GNUNET_PREFIX:address@hidden@}/bin:$$PATH;
+TESTS = \
+ $(check_PROGRAMS)
+endif
+
+EXTRA_DIST = \
+ cadet.h cadet_protocol.h \
+ test_cadet.conf \
+ test_cadet_drop.conf
+
Copied: gnunet/src/cadet/beautify_log.sh (from rev 33185,
gnunet/src/mesh/beautify_log.sh)
===================================================================
--- gnunet/src/cadet/beautify_log.sh (rev 0)
+++ gnunet/src/cadet/beautify_log.sh 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,18 @@
+#!/bin/sh
+grep "STARTING SERVICE " log > __tmp_peers
+SED_EXPR=""
+while read -r line; do
+ PEER=`echo $line | sed -e 's/.*\[\(....\)\].*/\1/'`
+ PID=`echo $line | sed -e 's/.*mesh-\([0-9]*\).*/\1/'`
+ echo "$PID => $PEER"
+ SED_EXPR="${SED_EXPR}s/mesh-\([a-z2]*\)-$PID/MESH \1 $PEER/;"
+ SED_EXPR="${SED_EXPR}s/mesh-$PID/MESH XXX $PEER/;"
+done < __tmp_peers
+rm __tmp_peers
+
+SED_EXPR="${SED_EXPR}s/mesh-api-/mesh-api-
/g"
+sed -e "$SED_EXPR" log > .log
+
+if [[ "`ps aux | grep "kwrite .lo[g]"`" = "" ]]; then
+ kwrite .log --geometry 960x1140-960 &
+fi
Copied: gnunet/src/cadet/cadet.h (from rev 33185, gnunet/src/mesh/cadet.h)
===================================================================
--- gnunet/src/cadet/cadet.h (rev 0)
+++ gnunet/src/cadet/cadet.h 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,351 @@
+/*
+ This file is part of GNUnet.
+ (C) 2001 - 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @author Bartlomiej Polot
+ * @file cadet/cadet.h
+ */
+
+#ifndef CADET_H_
+#define CADET_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0 /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include <stdint.h>
+
+#define CADET_DEBUG GNUNET_YES
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_peer_lib.h"
+#include "gnunet_core_service.h"
+#include "gnunet_protocols.h"
+#include <gnunet_cadet_service.h>
+
+/******************************************************************************/
+/************************** CONSTANTS
******************************/
+/******************************************************************************/
+
+#define GNUNET_CADET_LOCAL_CHANNEL_ID_CLI 0x80000000
+#define GNUNET_CADET_LOCAL_CHANNEL_ID_SERV 0xB0000000
+
+#define HIGH_PID 0xFFFF0000
+#define LOW_PID 0x0000FFFF
+
+#define PID_OVERFLOW(pid, max) (pid > HIGH_PID && max < LOW_PID)
+
+/******************************************************************************/
+/************************** MESSAGES
******************************/
+/******************************************************************************/
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Message for a client to register to the service
+ */
+struct GNUNET_CADET_ClientConnect
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT
+ *
+ * Size: sizeof(struct GNUNET_CADET_ClientConnect) +
+ * sizeof(CADET_ApplicationType) * applications +
+ * sizeof(uint16_t) * types
+ */
+ struct GNUNET_MessageHeader header;
+ /* uint32_t list_ports[] */
+};
+
+
+/**
+ * Type for channel numbering.
+ * - Local channel numbers given by the service (incoming) are >= 0xB0000000
+ * - Local channel numbers given by the client (created) are >= 0x80000000
+ * - Global channel numbers are < 0x80000000
+ */
+typedef uint32_t CADET_ChannelNumber;
+
+
+/**
+ * Message for a client to create and destroy channels.
+ */
+struct GNUNET_CADET_ChannelMessage
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_TUNNEL_[CREATE|DESTROY]
+ *
+ * Size: sizeof(struct GNUNET_CADET_ChannelMessage)
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * ID of a channel controlled by this client.
+ */
+ CADET_ChannelNumber channel_id GNUNET_PACKED;
+
+ /**
+ * Channel's peer
+ */
+ struct GNUNET_PeerIdentity peer;
+
+ /**
+ * Port of the channel.
+ */
+ uint32_t port GNUNET_PACKED;
+
+ /**
+ * Options.
+ */
+ uint32_t opt GNUNET_PACKED;
+};
+
+
+/**
+ * Message for cadet data traffic.
+ */
+struct GNUNET_CADET_LocalData
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * ID of the channel
+ */
+ uint32_t id GNUNET_PACKED;
+
+ /**
+ * Payload follows
+ */
+};
+
+
+/**
+ * Message to allow the client send more data to the service
+ * (always service -> client).
+ */
+struct GNUNET_CADET_LocalAck
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * ID of the channel allowed to send more data.
+ */
+ CADET_ChannelNumber channel_id GNUNET_PACKED;
+
+};
+
+
+/**
+ * Message to inform the client about channels in the service.
+ */
+struct GNUNET_CADET_LocalInfo
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO[_TUNNEL,_PEER]
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * ID of the channel allowed to send more data.
+ */
+ CADET_ChannelNumber channel_id GNUNET_PACKED;
+
+ /**
+ * ID of the owner of the channel (can be local peer).
+ */
+// struct GNUNET_PeerIdentity owner;
+
+ /**
+ * ID of the destination of the channel (can be local peer).
+ */
+ struct GNUNET_PeerIdentity peer;
+};
+
+
+/**
+ * Message to inform the client about one of the peers in the service.
+ */
+struct GNUNET_CADET_LocalInfoPeer
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER[S]
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Number of paths.
+ */
+ uint16_t paths GNUNET_PACKED;
+
+ /**
+ * Do we have a tunnel toward this peer?
+ */
+ int16_t tunnel GNUNET_PACKED;
+
+ /**
+ * ID of the destination of the tunnel (can be local peer).
+ */
+ struct GNUNET_PeerIdentity destination;
+
+ /* If type == PEER (no 'S'): GNUNET_PeerIdentity paths[]
+ * (each path ends in destination) */
+};
+
+/**
+ * Message to inform the client about one of the tunnels in the service.
+ */
+struct GNUNET_CADET_LocalInfoTunnel
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL[S]
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Number of channels.
+ */
+ uint32_t channels GNUNET_PACKED;
+
+ /**
+ * ID of the destination of the tunnel (can be local peer).
+ */
+ struct GNUNET_PeerIdentity destination;
+
+ /**
+ * Number of connections.
+ */
+ uint32_t connections GNUNET_PACKED;
+
+ /**
+ * Encryption state.
+ */
+ uint16_t estate GNUNET_PACKED;
+
+ /**
+ * Connection state.
+ */
+ uint16_t cstate GNUNET_PACKED;
+
+ /* If TUNNEL (no 'S'): GNUNET_PeerIdentity connection_ids[connections] */
+ /* If TUNNEL (no 'S'): uint32_t channel_ids[channels] */
+};
+
+
+GNUNET_NETWORK_STRUCT_END
+
+
+
+/**
+ * @brief Translate a fwd variable into a string representation, for logging.
+ *
+ * @param fwd Is FWD? (#GNUNET_YES or #GNUNET_NO)
+ *
+ * @return String representing FWD or BCK.
+ */
+char *
+GM_f2s (int fwd);
+
+
+/**
+ * Check if one pid is bigger than other, accounting for overflow.
+ *
+ * @param bigger Argument that should be bigger.
+ * @param smaller Argument that should be smaller.
+ *
+ * @return True if bigger (arg1) has a higher value than smaller (arg 2).
+ */
+int
+GM_is_pid_bigger (uint32_t bigger, uint32_t smaller);
+
+
+/**
+ * Get the higher ACK value out of two values, taking in account overflow.
+ *
+ * @param a First ACK value.
+ * @param b Second ACK value.
+ *
+ * @return Highest ACK value from the two.
+ */
+uint32_t
+GM_max_pid (uint32_t a, uint32_t b);
+
+
+/**
+ * Get the lower ACK value out of two values, taking in account overflow.
+ *
+ * @param a First ACK value.
+ * @param b Second ACK value.
+ *
+ * @return Lowest ACK value from the two.
+ */
+uint32_t
+GM_min_pid (uint32_t a, uint32_t b);
+
+
+/**
+ * Convert a 256 bit CadetHash into a 512 HashCode to use in GNUNET_h2s,
+ * multihashmap, and other HashCode-based functions.
+ *
+ * @param id A 256 bit hash to expand.
+ *
+ * @return A HashCode containing the original 256 bit hash right-padded with 0.
+ */
+const struct GNUNET_HashCode *
+GM_h2hc (const struct GNUNET_CADET_Hash *id);
+
+/**
+ * Get a string from a Cadet Hash (256 bits).
+ * WARNING: Not reentrant (based on GNUNET_h2s).
+ */
+const char *
+GM_h2s (const struct GNUNET_CADET_Hash *id);
+
+/**
+ * Convert a message type into a string to help debug
+ * Generated with:
+ * FIND: "#define ([^ ]+)[ ]*([0-9]+)"
+ * REPLACE: " case \2: return "\1"; break;"
+ *
+ * @param m Message type.
+ *
+ * @return Human readable string description.
+ */
+const char *
+GM_m2s (uint16_t m);
+
+#if 0 /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Copied: gnunet/src/cadet/cadet_api.c (from rev 33185,
gnunet/src/mesh/cadet_api.c)
===================================================================
--- gnunet/src/cadet/cadet_api.c (rev 0)
+++ gnunet/src/cadet/cadet_api.c 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,2141 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011 Christian Grothoff (and other contributing authors)
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file cadet/cadet_api.c
+ * @brief cadet api: client implementation of new cadet service
+ * @author Bartlomiej Polot
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_cadet_service.h"
+#include "cadet.h"
+#include "cadet_protocol.h"
+
+#define LOG(kind,...) GNUNET_log_from (kind, "cadet-api",__VA_ARGS__)
+
+/******************************************************************************/
+/************************ DATA STRUCTURES
****************************/
+/******************************************************************************/
+
+/**
+ * Transmission queue to the service
+ */
+struct GNUNET_CADET_TransmitHandle
+{
+
+ /**
+ * Double Linked list
+ */
+ struct GNUNET_CADET_TransmitHandle *next;
+
+ /**
+ * Double Linked list
+ */
+ struct GNUNET_CADET_TransmitHandle *prev;
+
+ /**
+ * Channel this message is sent on / for (may be NULL for control
messages).
+ */
+ struct GNUNET_CADET_Channel *channel;
+
+ /**
+ * Callback to obtain the message to transmit, or NULL if we
+ * got the message in 'data'. Notice that messages built
+ * by 'notify' need to be encapsulated with information about
+ * the 'target'.
+ */
+ GNUNET_CONNECTION_TransmitReadyNotify notify;
+
+ /**
+ * Closure for 'notify'
+ */
+ void *notify_cls;
+
+ /**
+ * How long is this message valid. Once the timeout has been
+ * reached, the message must no longer be sent. If this
+ * is a message with a 'notify' callback set, the 'notify'
+ * function should be called with 'buf' NULL and size 0.
+ */
+ struct GNUNET_TIME_Absolute timeout;
+
+ /**
+ * Task triggering a timeout, can be NO_TASK if the timeout is FOREVER.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+ /**
+ * Size of 'data' -- or the desired size of 'notify' if 'data' is NULL.
+ */
+ size_t size;
+};
+
+union CadetInfoCB {
+
+ /**
+ * Channel callback.
+ */
+ GNUNET_CADET_ChannelCB channel_cb;
+
+ /**
+ * Monitor callback
+ */
+ GNUNET_CADET_PeersCB peers_cb;
+
+ /**
+ * Monitor callback
+ */
+ GNUNET_CADET_PeerCB peer_cb;
+
+ /**
+ * Monitor callback
+ */
+ GNUNET_CADET_TunnelsCB tunnels_cb;
+
+ /**
+ * Tunnel callback.
+ */
+ GNUNET_CADET_TunnelCB tunnel_cb;
+};
+
+
+/**
+ * Opaque handle to the service.
+ */
+struct GNUNET_CADET_Handle
+{
+
+ /**
+ * Handle to the server connection, to send messages later
+ */
+ struct GNUNET_CLIENT_Connection *client;
+
+ /**
+ * Set of handlers used for processing incoming messages in the channels
+ */
+ const struct GNUNET_CADET_MessageHandler *message_handlers;
+
+ /**
+ * Number of handlers in the handlers array.
+ */
+ unsigned int n_handlers;
+
+ /**
+ * Ports open.
+ */
+ const uint32_t *ports;
+
+ /**
+ * Number of ports.
+ */
+ unsigned int n_ports;
+
+ /**
+ * Double linked list of the channels this client is connected to, head.
+ */
+ struct GNUNET_CADET_Channel *channels_head;
+
+ /**
+ * Double linked list of the channels this client is connected to, tail.
+ */
+ struct GNUNET_CADET_Channel *channels_tail;
+
+ /**
+ * Callback for inbound channel creation
+ */
+ GNUNET_CADET_InboundChannelNotificationHandler *new_channel;
+
+ /**
+ * Callback for inbound channel disconnection
+ */
+ GNUNET_CADET_ChannelEndHandler *cleaner;
+
+ /**
+ * Handle to cancel pending transmissions in case of disconnection
+ */
+ struct GNUNET_CLIENT_TransmitHandle *th;
+
+ /**
+ * Closure for all the handlers given by the client
+ */
+ void *cls;
+
+ /**
+ * Messages to send to the service, head.
+ */
+ struct GNUNET_CADET_TransmitHandle *th_head;
+
+ /**
+ * Messages to send to the service, tail.
+ */
+ struct GNUNET_CADET_TransmitHandle *th_tail;
+
+ /**
+ * chid of the next channel to create (to avoid reusing IDs often)
+ */
+ CADET_ChannelNumber next_chid;
+
+ /**
+ * Have we started the task to receive messages from the service
+ * yet? We do this after we send the 'CADET_LOCAL_CONNECT' message.
+ */
+ int in_receive;
+
+ /**
+ * Configuration given by the client, in case of reconnection
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * Time to the next reconnect in case one reconnect fails
+ */
+ struct GNUNET_TIME_Relative reconnect_time;
+
+ /**
+ * Task for trying to reconnect.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
+
+ /**
+ * Callback for an info task (only one active at a time).
+ */
+ union CadetInfoCB info_cb;
+
+ /**
+ * Info callback closure for @c info_cb.
+ */
+ void *info_cls;
+};
+
+
+/**
+ * Description of a peer
+ */
+struct GNUNET_CADET_Peer
+{
+ /**
+ * ID of the peer in short form
+ */
+ GNUNET_PEER_Id id;
+
+ /**
+ * Channel this peer belongs to
+ */
+ struct GNUNET_CADET_Channel *t;
+};
+
+
+/**
+ * Opaque handle to a channel.
+ */
+struct GNUNET_CADET_Channel
+{
+
+ /**
+ * DLL next
+ */
+ struct GNUNET_CADET_Channel *next;
+
+ /**
+ * DLL prev
+ */
+ struct GNUNET_CADET_Channel *prev;
+
+ /**
+ * Handle to the cadet this channel belongs to
+ */
+ struct GNUNET_CADET_Handle *cadet;
+
+ /**
+ * Local ID of the channel
+ */
+ CADET_ChannelNumber chid;
+
+ /**
+ * Port number.
+ */
+ uint32_t port;
+
+ /**
+ * Other end of the channel.
+ */
+ GNUNET_PEER_Id peer;
+
+ /**
+ * Any data the caller wants to put in here
+ */
+ void *ctx;
+
+ /**
+ * Size of packet queued in this channel
+ */
+ unsigned int packet_size;
+
+ /**
+ * Channel options: reliability, etc.
+ */
+ enum GNUNET_CADET_ChannelOption options;
+
+ /**
+ * Are we allowed to send to the service?
+ */
+ int allow_send;
+
+};
+
+
+/**
+ * Implementation state for cadet's message queue.
+ */
+struct CadetMQState
+{
+ /**
+ * The current transmit handle, or NULL
+ * if no transmit is active.
+ */
+ struct GNUNET_CADET_TransmitHandle *th;
+
+ /**
+ * Channel to send the data over.
+ */
+ struct GNUNET_CADET_Channel *channel;
+};
+
+
+/******************************************************************************/
+/*********************** DECLARATIONS
*************************/
+/******************************************************************************/
+
+/**
+ * Function called to send a message to the service.
+ * "buf" will be NULL and "size" zero if the socket was closed for writing in
+ * the meantime.
+ *
+ * @param cls closure, the cadet handle
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the connect message
+ * @return number of bytes written to buf
+ */
+static size_t
+send_callback (void *cls, size_t size, void *buf);
+
+
+/******************************************************************************/
+/*********************** AUXILIARY FUNCTIONS
*************************/
+/******************************************************************************/
+
+/**
+ * Check if transmission is a payload packet.
+ *
+ * @param th Transmission handle.
+ *
+ * @return GNUNET_YES if it is a payload packet,
+ * GNUNET_NO if it is a cadet management packet.
+ */
+static int
+th_is_payload (struct GNUNET_CADET_TransmitHandle *th)
+{
+ return (th->notify != NULL) ? GNUNET_YES : GNUNET_NO;
+}
+
+
+/**
+ * Check whether there is any message ready in the queue and find the size.
+ *
+ * @param h Cadet handle.
+ *
+ * @return The size of the first ready message in the queue,
+ * 0 if there is none.
+ */
+static size_t
+message_ready_size (struct GNUNET_CADET_Handle *h)
+{
+ struct GNUNET_CADET_TransmitHandle *th;
+ struct GNUNET_CADET_Channel *ch;
+
+ for (th = h->th_head; NULL != th; th = th->next)
+ {
+ ch = th->channel;
+ if (GNUNET_NO == th_is_payload (th))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "# message internal\n");
+ return th->size;
+ }
+ if (GNUNET_YES == ch->allow_send)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "# message payload ok\n");
+ return th->size;
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * Get the channel handler for the channel specified by id from the given
handle
+ * @param h Cadet handle
+ * @param chid ID of the wanted channel
+ * @return handle to the required channel or NULL if not found
+ */
+static struct GNUNET_CADET_Channel *
+retrieve_channel (struct GNUNET_CADET_Handle *h, CADET_ChannelNumber chid)
+{
+ struct GNUNET_CADET_Channel *ch;
+
+ ch = h->channels_head;
+ while (ch != NULL)
+ {
+ if (ch->chid == chid)
+ return ch;
+ ch = ch->next;
+ }
+ return NULL;
+}
+
+
+/**
+ * Create a new channel and insert it in the channel list of the cadet handle
+ *
+ * @param h Cadet handle
+ * @param chid Desired chid of the channel, 0 to assign one automatically.
+ *
+ * @return Handle to the created channel.
+ */
+static struct GNUNET_CADET_Channel *
+create_channel (struct GNUNET_CADET_Handle *h, CADET_ChannelNumber chid)
+{
+ struct GNUNET_CADET_Channel *ch;
+
+ ch = GNUNET_new (struct GNUNET_CADET_Channel);
+ GNUNET_CONTAINER_DLL_insert (h->channels_head, h->channels_tail, ch);
+ ch->cadet = h;
+ if (0 == chid)
+ {
+ ch->chid = h->next_chid;
+ while (NULL != retrieve_channel (h, h->next_chid))
+ {
+ h->next_chid++;
+ h->next_chid &= ~GNUNET_CADET_LOCAL_CHANNEL_ID_SERV;
+ h->next_chid |= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
+ }
+ }
+ else
+ {
+ ch->chid = chid;
+ }
+ ch->allow_send = GNUNET_NO;
+ return ch;
+}
+
+
+/**
+ * Destroy the specified channel.
+ * - Destroys all peers, calling the disconnect callback on each if needed
+ * - Cancels all outgoing traffic for that channel, calling respective notifys
+ * - Calls cleaner if channel was inbound
+ * - Frees all memory used
+ *
+ * @param ch Pointer to the channel.
+ * @param call_cleaner Whether to call the cleaner handler.
+ *
+ * @return Handle to the required channel or NULL if not found.
+ */
+static void
+destroy_channel (struct GNUNET_CADET_Channel *ch, int call_cleaner)
+{
+ struct GNUNET_CADET_Handle *h;
+ struct GNUNET_CADET_TransmitHandle *th;
+ struct GNUNET_CADET_TransmitHandle *next;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " destroy_channel %X\n", ch->chid);
+
+ if (NULL == ch)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ h = ch->cadet;
+
+ GNUNET_CONTAINER_DLL_remove (h->channels_head, h->channels_tail, ch);
+
+ /* signal channel destruction */
+ if ( (NULL != h->cleaner) && (0 != ch->peer) && (GNUNET_YES == call_cleaner)
)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " calling cleaner\n");
+ h->cleaner (h->cls, ch, ch->ctx);
+ }
+
+ /* check that clients did not leave messages behind in the queue */
+ for (th = h->th_head; NULL != th; th = next)
+ {
+ next = th->next;
+ if (th->channel != ch)
+ continue;
+ /* Clients should have aborted their requests already.
+ * Management traffic should be ok, as clients can't cancel that.
+ * If the service crashed and we are reconnecting, it's ok.
+ */
+ GNUNET_break (GNUNET_NO == th_is_payload (th)
+ || GNUNET_NO == h->in_receive);
+ GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
+
+ /* clean up request */
+ if (GNUNET_SCHEDULER_NO_TASK != th->timeout_task)
+ GNUNET_SCHEDULER_cancel (th->timeout_task);
+ GNUNET_free (th);
+ }
+
+ /* if there are no more pending requests with cadet service, cancel active
request */
+ /* Note: this should be unnecessary... */
+ if ((0 == message_ready_size (h)) && (NULL != h->th))
+ {
+ GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
+ h->th = NULL;
+ }
+
+ if (0 != ch->peer)
+ GNUNET_PEER_change_rc (ch->peer, -1);
+ GNUNET_free (ch);
+ return;
+}
+
+
+/**
+ * Notify client that the transmission has timed out
+ *
+ * @param cls closure
+ * @param tc task context
+ */
+static void
+timeout_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_CADET_TransmitHandle *th = cls;
+ struct GNUNET_CADET_Handle *cadet;
+
+ cadet = th->channel->cadet;
+ GNUNET_CONTAINER_DLL_remove (cadet->th_head, cadet->th_tail, th);
+ th->channel->packet_size = 0;
+ if (GNUNET_YES == th_is_payload (th))
+ th->notify (th->notify_cls, 0, NULL);
+ GNUNET_free (th);
+ if ((0 == message_ready_size (cadet)) && (NULL != cadet->th))
+ {
+ /* nothing ready to transmit, no point in asking for transmission */
+ GNUNET_CLIENT_notify_transmit_ready_cancel (cadet->th);
+ cadet->th = NULL;
+ }
+}
+
+
+/**
+ * Add a transmit handle to the transmission queue and set the
+ * timeout if needed.
+ *
+ * @param h cadet handle with the queue head and tail
+ * @param th handle to the packet to be transmitted
+ */
+static void
+add_to_queue (struct GNUNET_CADET_Handle *h,
+ struct GNUNET_CADET_TransmitHandle *th)
+{
+ GNUNET_CONTAINER_DLL_insert_tail (h->th_head, h->th_tail, th);
+ if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us == th->timeout.abs_value_us)
+ return;
+ th->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
+ (th->timeout), &timeout_transmission, th);
+}
+
+
+/**
+ * Auxiliary function to send an already constructed packet to the service.
+ * Takes care of creating a new queue element, copying the message and
+ * calling the tmt_rdy function if necessary.
+ *
+ * @param h cadet handle
+ * @param msg message to transmit
+ * @param channel channel this send is related to (NULL if N/A)
+ */
+static void
+send_packet (struct GNUNET_CADET_Handle *h,
+ const struct GNUNET_MessageHeader *msg,
+ struct GNUNET_CADET_Channel *channel);
+
+
+/**
+ * Send an ack on the channel to confirm the processing of a message.
+ *
+ * @param ch Channel on which to send the ACK.
+ */
+static void
+send_ack (struct GNUNET_CADET_Channel *ch)
+{
+ struct GNUNET_CADET_LocalAck msg;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending ACK on channel %X\n", ch->chid);
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
+ msg.header.size = htons (sizeof (msg));
+ msg.channel_id = htonl (ch->chid);
+
+ send_packet (ch->cadet, &msg.header, ch);
+ return;
+}
+
+
+
+/**
+ * Reconnect callback: tries to reconnect again after a failer previous
+ * reconnecttion
+ * @param cls closure (cadet handle)
+ * @param tc task context
+ */
+static void
+reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Send a connect packet to the service with the applications and types
+ * requested by the user.
+ *
+ * @param h The cadet handle.
+ *
+ */
+static void
+send_connect (struct GNUNET_CADET_Handle *h)
+{
+ size_t size;
+
+ size = sizeof (struct GNUNET_CADET_ClientConnect);
+ size += h->n_ports * sizeof (uint32_t);
+ {
+ char buf[size] GNUNET_ALIGN;
+ struct GNUNET_CADET_ClientConnect *msg;
+ uint32_t *ports;
+ uint16_t i;
+
+ /* build connection packet */
+ msg = (struct GNUNET_CADET_ClientConnect *) buf;
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT);
+ msg->header.size = htons (size);
+ ports = (uint32_t *) &msg[1];
+ for (i = 0; i < h->n_ports; i++)
+ {
+ ports[i] = htonl (h->ports[i]);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " port %u\n",
+ h->ports[i]);
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending %lu bytes long message with %u ports\n",
+ ntohs (msg->header.size), h->n_ports);
+ send_packet (h, &msg->header, NULL);
+ }
+}
+
+
+/**
+ * Reconnect to the service, retransmit all infomation to try to restore the
+ * original state.
+ *
+ * @param h handle to the cadet
+ *
+ * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...)
+ */
+static int
+do_reconnect (struct GNUNET_CADET_Handle *h)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "******* RECONNECT *******\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "******** on %p *******\n", h);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n");
+
+ /* disconnect */
+ if (NULL != h->th)
+ {
+ GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
+ h->th = NULL;
+ }
+ if (NULL != h->client)
+ {
+ GNUNET_CLIENT_disconnect (h->client);
+ }
+
+ /* connect again */
+ h->client = GNUNET_CLIENT_connect ("cadet", h->cfg);
+ if (h->client == NULL)
+ {
+ h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time,
+ &reconnect_cbk, h);
+ h->reconnect_time =
+ GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS,
+ GNUNET_TIME_relative_multiply
+ (h->reconnect_time, 2));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Next retry in %s\n",
+ GNUNET_STRINGS_relative_time_to_string (h->reconnect_time,
+ GNUNET_NO));
+ GNUNET_break (0);
+ return GNUNET_NO;
+ }
+ else
+ {
+ h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
+ }
+ send_connect (h);
+ return GNUNET_YES;
+}
+
+/**
+ * Reconnect callback: tries to reconnect again after a failer previous
+ * reconnecttion
+ * @param cls closure (cadet handle)
+ * @param tc task context
+ */
+static void
+reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_CADET_Handle *h = cls;
+
+ h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+ do_reconnect (h);
+}
+
+
+/**
+ * Reconnect to the service, retransmit all infomation to try to restore the
+ * original state.
+ *
+ * @param h handle to the cadet
+ *
+ * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...)
+ */
+static void
+reconnect (struct GNUNET_CADET_Handle *h)
+{
+ struct GNUNET_CADET_Channel *ch;
+ struct GNUNET_CADET_Channel *next;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Requested RECONNECT, destroying all channels\n");
+ h->in_receive = GNUNET_NO;
+ for (ch = h->channels_head; NULL != ch; ch = next)
+ {
+ next = ch->next;
+ destroy_channel (ch, GNUNET_YES);
+ }
+ if (GNUNET_SCHEDULER_NO_TASK == h->reconnect_task)
+ h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time,
+ &reconnect_cbk, h);
+}
+
+
+/******************************************************************************/
+/*********************** RECEIVE HANDLERS
****************************/
+/******************************************************************************/
+
+/**
+ * Process the new channel notification and add it to the channels in the
handle
+ *
+ * @param h The cadet handle
+ * @param msg A message with the details of the new incoming channel
+ */
+static void
+process_channel_created (struct GNUNET_CADET_Handle *h,
+ const struct GNUNET_CADET_ChannelMessage *msg)
+{
+ struct GNUNET_CADET_Channel *ch;
+ CADET_ChannelNumber chid;
+ uint32_t port;
+
+ chid = ntohl (msg->channel_id);
+ port = ntohl (msg->port);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating incoming channel %X:%u\n", chid,
port);
+ if (chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ if (NULL != h->new_channel)
+ {
+ void *ctx;
+
+ ch = create_channel (h, chid);
+ ch->allow_send = GNUNET_NO;
+ ch->peer = GNUNET_PEER_intern (&msg->peer);
+ ch->cadet = h;
+ ch->chid = chid;
+ ch->port = port;
+ ch->options = ntohl (msg->opt);
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " created channel %p\n", ch);
+ ctx = h->new_channel (h->cls, ch, &msg->peer, ch->port, ch->options);
+ if (NULL != ctx)
+ ch->ctx = ctx;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "User notified\n");
+ }
+ else
+ {
+ struct GNUNET_CADET_ChannelMessage d_msg;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "No handler for incoming channels\n");
+
+ d_msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
+ d_msg.header.size = htons (sizeof (struct GNUNET_CADET_ChannelMessage));
+ d_msg.channel_id = msg->channel_id;
+ memset (&d_msg.peer, 0, sizeof (struct GNUNET_PeerIdentity));
+ d_msg.port = 0;
+ d_msg.opt = 0;
+
+ send_packet (h, &d_msg.header, NULL);
+ }
+ return;
+}
+
+
+/**
+ * Process the channel destroy notification and free associated resources
+ *
+ * @param h The cadet handle
+ * @param msg A message with the details of the channel being destroyed
+ */
+static void
+process_channel_destroy (struct GNUNET_CADET_Handle *h,
+ const struct GNUNET_CADET_ChannelMessage *msg)
+{
+ struct GNUNET_CADET_Channel *ch;
+ CADET_ChannelNumber chid;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel Destroy received from service\n");
+ chid = ntohl (msg->channel_id);
+ ch = retrieve_channel (h, chid);
+
+ if (NULL == ch)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "channel %X unknown\n", chid);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " destroying channel %X\n", ch->chid);
+ destroy_channel (ch, GNUNET_YES);
+}
+
+
+/**
+ * Process the incoming data packets, call appropriate handlers.
+ *
+ * @param h The cadet handle
+ * @param message A message encapsulating the data
+ */
+static void
+process_incoming_data (struct GNUNET_CADET_Handle *h,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct GNUNET_MessageHeader *payload;
+ const struct GNUNET_CADET_MessageHandler *handler;
+ struct GNUNET_CADET_LocalData *dmsg;
+ struct GNUNET_CADET_Channel *ch;
+ size_t size;
+ unsigned int i;
+ uint16_t type;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a data message!\n");
+ dmsg = (struct GNUNET_CADET_LocalData *) message;
+ ch = retrieve_channel (h, ntohl (dmsg->id));
+ if (NULL == ch)
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ payload = (struct GNUNET_MessageHeader *) &dmsg[1];
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " %s data on channel %s [%X]\n",
+ GM_f2s (ch->chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV),
+ GNUNET_i2s (GNUNET_PEER_resolve2 (ch->peer)), ntohl (dmsg->id));
+
+ size = ntohs (message->size);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " %u bytes\n", size);
+
+ if (NULL == ch)
+ {
+ /* Channel was ignored/destroyed, probably service didn't get it yet */
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ignored!\n");
+ return;
+ }
+ type = ntohs (payload->type);
+ size = ntohs (payload->size);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " payload type %s\n", GM_m2s (type));
+ for (i = 0; i < h->n_handlers; i++)
+ {
+ handler = &h->message_handlers[i];
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " checking handler for type %u\n",
+ handler->type);
+ if (handler->type == type)
+ {
+ if (GNUNET_OK !=
+ handler->callback (h->cls, ch, &ch->ctx, payload))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "callback caused disconnection\n");
+ GNUNET_CADET_channel_destroy (ch);
+ return;
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "callback completed successfully\n");
+ return;
+ }
+ }
+ }
+}
+
+
+/**
+ * Process a local ACK message, enabling the client to send
+ * more data to the service.
+ *
+ * @param h Cadet handle.
+ * @param message Message itself.
+ */
+static void
+process_ack (struct GNUNET_CADET_Handle *h,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_CADET_LocalAck *msg;
+ struct GNUNET_CADET_Channel *ch;
+ CADET_ChannelNumber chid;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Got an ACK!\n");
+ msg = (struct GNUNET_CADET_LocalAck *) message;
+ chid = ntohl (msg->channel_id);
+ ch = retrieve_channel (h, chid);
+ if (NULL == ch)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "ACK on unknown channel %X\n", chid);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X!\n", ch->chid);
+ ch->allow_send = GNUNET_YES;
+ if (NULL == h->th && 0 < ch->packet_size)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " tmt rdy was NULL, requesting!\n");
+ h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, ch->packet_size,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_YES, &send_callback,
h);
+ }
+}
+
+
+/*
+ * Process a local reply about info on all channels, pass info to the user.
+ *
+ * @param h Cadet handle.
+ * @param message Message itself.
+ */
+// static void
+// process_get_channels (struct GNUNET_CADET_Handle *h,
+// const struct GNUNET_MessageHeader *message)
+// {
+// struct GNUNET_CADET_LocalInfo *msg;
+//
+// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Get Channels messasge received\n");
+//
+// if (NULL == h->channels_cb)
+// {
+// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " ignored\n");
+// return;
+// }
+//
+// msg = (struct GNUNET_CADET_LocalInfo *) message;
+// if (ntohs (message->size) !=
+// (sizeof (struct GNUNET_CADET_LocalInfo) +
+// sizeof (struct GNUNET_PeerIdentity)))
+// {
+// GNUNET_break_op (0);
+// GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+// "Get channels message: size %hu - expected %u\n",
+// ntohs (message->size),
+// sizeof (struct GNUNET_CADET_LocalInfo));
+// return;
+// }
+// h->channels_cb (h->channels_cls,
+// ntohl (msg->channel_id),
+// &msg->owner,
+// &msg->destination);
+// }
+
+
+
+/*
+ * Process a local monitor_channel reply, pass info to the user.
+ *
+ * @param h Cadet handle.
+ * @param message Message itself.
+ */
+// static void
+// process_show_channel (struct GNUNET_CADET_Handle *h,
+// const struct GNUNET_MessageHeader *message)
+// {
+// struct GNUNET_CADET_LocalInfo *msg;
+// size_t esize;
+//
+// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Show Channel messasge received\n");
+//
+// if (NULL == h->channel_cb)
+// {
+// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " ignored\n");
+// return;
+// }
+//
+// /* Verify message sanity */
+// msg = (struct GNUNET_CADET_LocalInfo *) message;
+// esize = sizeof (struct GNUNET_CADET_LocalInfo);
+// if (ntohs (message->size) != esize)
+// {
+// GNUNET_break_op (0);
+// GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+// "Show channel message: size %hu - expected %u\n",
+// ntohs (message->size),
+// esize);
+//
+// h->channel_cb (h->channel_cls, NULL, NULL);
+// h->channel_cb = NULL;
+// h->channel_cls = NULL;
+//
+// return;
+// }
+//
+// h->channel_cb (h->channel_cls,
+// &msg->destination,
+// &msg->owner);
+// }
+
+
+
+/**
+ * Process a local reply about info on all tunnels, pass info to the user.
+ *
+ * @param h Cadet handle.
+ * @param message Message itself.
+ */
+static void
+process_get_peers (struct GNUNET_CADET_Handle *h,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_CADET_LocalInfoPeer *msg;
+ uint16_t size;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Get Peer messasge received\n");
+
+ if (NULL == h->info_cb.peers_cb)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ignored\n");
+ return;
+ }
+
+ size = ntohs (message->size);
+ if (sizeof (struct GNUNET_CADET_LocalInfoPeer) > size)
+ {
+ h->info_cb.peers_cb (h->info_cls, NULL, -1, 0, 0);
+ h->info_cb.peers_cb = NULL;
+ h->info_cls = NULL;
+ return;
+ }
+
+ msg = (struct GNUNET_CADET_LocalInfoPeer *) message;
+ h->info_cb.peers_cb (h->info_cls, &msg->destination,
+ (int) ntohs (msg->tunnel),
+ (unsigned int ) ntohs (msg->paths),
+ 0);
+}
+
+
+/**
+ * Process a local peer info reply, pass info to the user.
+ *
+ * @param h Cadet handle.
+ * @param message Message itself.
+ */
+static void
+process_get_peer (struct GNUNET_CADET_Handle *h,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_CADET_LocalInfoTunnel *msg;
+ size_t esize;
+ size_t msize;
+ unsigned int ch_n;
+ unsigned int c_n;
+ struct GNUNET_CADET_Hash *conns;
+ CADET_ChannelNumber *chns;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Get Tunnel messasge received\n");
+ if (NULL == h->info_cb.tunnel_cb)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ignored\n");
+ return;
+ }
+
+ /* Verify message sanity */
+ msg = (struct GNUNET_CADET_LocalInfoTunnel *) message;
+ msize = ntohs (message->size);
+ esize = sizeof (struct GNUNET_CADET_LocalInfoTunnel);
+ if (esize > msize)
+ {
+ GNUNET_break_op (0);
+ h->info_cb.tunnel_cb (h->info_cls, NULL, 0, 0, NULL, NULL, 0, 0);
+ goto clean_cls;
+ }
+ ch_n = ntohl (msg->channels);
+ c_n = ntohl (msg->connections);
+ esize += ch_n * sizeof (CADET_ChannelNumber);
+ esize += c_n * sizeof (struct GNUNET_CADET_Hash);
+ if (msize != esize)
+ {
+ GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "m:%u, e: %u (%u ch, %u conn)\n",
+ msize, esize, ch_n, c_n);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%u (%u ch, %u conn)\n",
+ sizeof (struct GNUNET_CADET_LocalInfoTunnel),
+ sizeof (CADET_ChannelNumber), sizeof (struct GNUNET_HashCode));
+ h->info_cb.tunnel_cb (h->info_cls, NULL, 0, 0, NULL, NULL, 0, 0);
+ goto clean_cls;
+ }
+
+ /* Call Callback with tunnel info. */
+ conns = (struct GNUNET_CADET_Hash *) &msg[1];
+ chns = (CADET_ChannelNumber *) &conns[c_n];
+ h->info_cb.tunnel_cb (h->info_cls, &msg->destination,
+ ch_n, c_n, chns, conns,
+ ntohs (msg->estate), ntohs (msg->cstate));
+
+ clean_cls:
+ h->info_cb.tunnel_cb = NULL;
+ h->info_cls = NULL;
+}
+
+
+/**
+ * Process a local reply about info on all tunnels, pass info to the user.
+ *
+ * @param h Cadet handle.
+ * @param message Message itself.
+ */
+static void
+process_get_tunnels (struct GNUNET_CADET_Handle *h,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_CADET_LocalInfoTunnel *msg;
+ uint16_t size;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Get Tunnels messasge received\n");
+
+ if (NULL == h->info_cb.tunnels_cb)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ignored\n");
+ return;
+ }
+
+ size = ntohs (message->size);
+ if (sizeof (struct GNUNET_CADET_LocalInfoTunnel) > size)
+ {
+ h->info_cb.tunnels_cb (h->info_cls, NULL, 0, 0, 0, 0);
+ h->info_cb.tunnels_cb = NULL;
+ h->info_cls = NULL;
+ return;
+ }
+
+ msg = (struct GNUNET_CADET_LocalInfoTunnel *) message;
+ h->info_cb.tunnels_cb (h->info_cls, &msg->destination,
+ ntohl (msg->channels), ntohl (msg->connections),
+ ntohs (msg->estate), ntohs (msg->cstate));
+
+}
+
+
+/**
+ * Process a local tunnel info reply, pass info to the user.
+ *
+ * @param h Cadet handle.
+ * @param message Message itself.
+ */
+static void
+process_get_tunnel (struct GNUNET_CADET_Handle *h,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_CADET_LocalInfoTunnel *msg;
+ size_t esize;
+ size_t msize;
+ unsigned int ch_n;
+ unsigned int c_n;
+ struct GNUNET_CADET_Hash *conns;
+ CADET_ChannelNumber *chns;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Get Tunnel messasge received\n");
+ if (NULL == h->info_cb.tunnel_cb)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ignored\n");
+ return;
+ }
+
+ /* Verify message sanity */
+ msg = (struct GNUNET_CADET_LocalInfoTunnel *) message;
+ msize = ntohs (message->size);
+ esize = sizeof (struct GNUNET_CADET_LocalInfoTunnel);
+ if (esize > msize)
+ {
+ GNUNET_break_op (0);
+ h->info_cb.tunnel_cb (h->info_cls, NULL, 0, 0, NULL, NULL, 0, 0);
+ goto clean_cls;
+ }
+ ch_n = ntohl (msg->channels);
+ c_n = ntohl (msg->connections);
+ esize += ch_n * sizeof (CADET_ChannelNumber);
+ esize += c_n * sizeof (struct GNUNET_CADET_Hash);
+ if (msize != esize)
+ {
+ GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "m:%u, e: %u (%u ch, %u conn)\n",
+ msize, esize, ch_n, c_n);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%u (%u ch, %u conn)\n",
+ sizeof (struct GNUNET_CADET_LocalInfoTunnel),
+ sizeof (CADET_ChannelNumber), sizeof (struct GNUNET_HashCode));
+ h->info_cb.tunnel_cb (h->info_cls, NULL, 0, 0, NULL, NULL, 0, 0);
+ goto clean_cls;
+ }
+
+ /* Call Callback with tunnel info. */
+ conns = (struct GNUNET_CADET_Hash *) &msg[1];
+ chns = (CADET_ChannelNumber *) &conns[c_n];
+ h->info_cb.tunnel_cb (h->info_cls, &msg->destination,
+ ch_n, c_n, chns, conns,
+ ntohs (msg->estate), ntohs (msg->cstate));
+
+clean_cls:
+ h->info_cb.tunnel_cb = NULL;
+ h->info_cls = NULL;
+}
+
+
+/**
+ * Function to process all messages received from the service
+ *
+ * @param cls closure
+ * @param msg message received, NULL on timeout or fatal error
+ */
+static void
+msg_received (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_CADET_Handle *h = cls;
+ uint16_t type;
+
+ if (msg == NULL)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Cadet service disconnected, reconnecting\n", h);
+ reconnect (h);
+ return;
+ }
+ type = ntohs (msg->type);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Received a message: %s\n",
+ GM_m2s (type));
+ switch (type)
+ {
+ /* Notify of a new incoming channel */
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE:
+ process_channel_created (h, (struct GNUNET_CADET_ChannelMessage *) msg);
+ break;
+ /* Notify of a channel disconnection */
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: /* TODO separate(gid
problem)*/
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK:
+ process_channel_destroy (h, (struct GNUNET_CADET_ChannelMessage *) msg);
+ break;
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA:
+ process_incoming_data (h, msg);
+ break;
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK:
+ process_ack (h, msg);
+ break;
+// case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNELS:
+// process_get_channels (h, msg);
+// break;
+// case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL:
+// process_show_channel (h, msg);
+// break;
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS:
+ process_get_peers (h, msg);
+ break;
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER:
+ process_get_peer (h, msg);
+ break;
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS:
+ process_get_tunnels (h, msg);
+ break;
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL:
+ process_get_tunnel (h, msg);
+ break;
+// case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL:
+// process_show_channel (h, msg);
+// break;
+ default:
+ /* We shouldn't get any other packages, log and ignore */
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "unsolicited message form service (type %s)\n",
+ GM_m2s (ntohs (msg->type)));
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "message processed\n");
+ if (GNUNET_YES == h->in_receive)
+ {
+ GNUNET_CLIENT_receive (h->client, &msg_received, h,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "in receive off, not calling CLIENT_receive\n");
+ }
+}
+
+
+/******************************************************************************/
+/************************ SEND FUNCTIONS
****************************/
+/******************************************************************************/
+
+/**
+ * Function called to send a message to the service.
+ * "buf" will be NULL and "size" zero if the socket was closed for writing in
+ * the meantime.
+ *
+ * @param cls closure, the cadet handle
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the connect message
+ * @return number of bytes written to buf
+ */
+static size_t
+send_callback (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_CADET_Handle *h = cls;
+ struct GNUNET_CADET_TransmitHandle *th;
+ struct GNUNET_CADET_TransmitHandle *next;
+ struct GNUNET_CADET_Channel *ch;
+ char *cbuf = buf;
+ size_t tsize;
+ size_t psize;
+ size_t nsize;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "# Send packet() Buffer %u\n", size);
+ if ((0 == size) || (NULL == buf))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "# Received NULL send callback on %p\n", h);
+ reconnect (h);
+ h->th = NULL;
+ return 0;
+ }
+ tsize = 0;
+ next = h->th_head;
+ nsize = message_ready_size (h);
+ while ((NULL != (th = next)) && (0 < nsize) && (size >= nsize))
+ {
+ ch = th->channel;
+ if (GNUNET_YES == th_is_payload (th))
+ {
+ struct GNUNET_CADET_LocalData *dmsg;
+ struct GNUNET_MessageHeader *mh;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "# payload\n");
+ if (GNUNET_NO == ch->allow_send)
+ {
+ /* This channel is not ready to transmit yet, try next message */
+ next = th->next;
+ continue;
+ }
+ ch->packet_size = 0;
+ GNUNET_assert (size >= th->size);
+ dmsg = (struct GNUNET_CADET_LocalData *) cbuf;
+ mh = (struct GNUNET_MessageHeader *) &dmsg[1];
+ psize = th->notify (th->notify_cls,
+ size - sizeof (struct GNUNET_CADET_LocalData),
+ mh);
+ if (psize > 0)
+ {
+ psize += sizeof (struct GNUNET_CADET_LocalData);
+ GNUNET_assert (size >= psize);
+ dmsg->header.size = htons (psize);
+ dmsg->id = htonl (ch->chid);
+ dmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "# payload type %s\n",
+ GM_m2s (ntohs (mh->type)));
+ ch->allow_send = GNUNET_NO;
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "# callback returned size 0, "
+ "application canceled transmission\n");
+ }
+ }
+ else
+ {
+ struct GNUNET_MessageHeader *mh = (struct GNUNET_MessageHeader *) &th[1];
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "# cadet internal traffic, type %s\n",
+ GM_m2s (ntohs (mh->type)));
+ memcpy (cbuf, &th[1], th->size);
+ psize = th->size;
+ }
+ if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (th->timeout_task);
+ GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
+ GNUNET_free (th);
+ next = h->th_head;
+ nsize = message_ready_size (h);
+ cbuf += psize;
+ size -= psize;
+ tsize += psize;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "# total size: %u\n", tsize);
+ h->th = NULL;
+ size = message_ready_size (h);
+ if (0 != size)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "# next size: %u\n", size);
+ h->th =
+ GNUNET_CLIENT_notify_transmit_ready (h->client, size,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_YES, &send_callback, h);
+ }
+ else
+ {
+ if (NULL != h->th_head)
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "# can't transmit any more\n");
+ else
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "# nothing left to transmit\n");
+ }
+ if (GNUNET_NO == h->in_receive)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "# start receiving from service\n");
+ h->in_receive = GNUNET_YES;
+ GNUNET_CLIENT_receive (h->client, &msg_received, h,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "# Send packet() END\n");
+ return tsize;
+}
+
+
+/**
+ * Auxiliary function to send an already constructed packet to the service.
+ * Takes care of creating a new queue element, copying the message and
+ * calling the tmt_rdy function if necessary.
+ *
+ * @param h cadet handle
+ * @param msg message to transmit
+ * @param channel channel this send is related to (NULL if N/A)
+ */
+static void
+send_packet (struct GNUNET_CADET_Handle *h,
+ const struct GNUNET_MessageHeader *msg,
+ struct GNUNET_CADET_Channel *channel)
+{
+ struct GNUNET_CADET_TransmitHandle *th;
+ size_t msize;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Sending message to service: %s\n",
+ GM_m2s(ntohs(msg->type)));
+ msize = ntohs (msg->size);
+ th = GNUNET_malloc (sizeof (struct GNUNET_CADET_TransmitHandle) + msize);
+ th->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
+ th->size = msize;
+ th->channel = channel;
+ memcpy (&th[1], msg, msize);
+ add_to_queue (h, th);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " queued\n");
+ if (NULL != h->th)
+ return;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " calling ntfy tmt rdy for %u bytes\n",
msize);
+ h->th =
+ GNUNET_CLIENT_notify_transmit_ready (h->client, msize,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_YES, &send_callback, h);
+}
+
+
+/******************************************************************************/
+/********************** API CALL DEFINITIONS
*************************/
+/******************************************************************************/
+
+struct GNUNET_CADET_Handle *
+GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, void *cls,
+ GNUNET_CADET_InboundChannelNotificationHandler
new_channel,
+ GNUNET_CADET_ChannelEndHandler cleaner,
+ const struct GNUNET_CADET_MessageHandler *handlers,
+ const uint32_t *ports)
+{
+ struct GNUNET_CADET_Handle *h;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_CADET_connect()\n");
+ h = GNUNET_new (struct GNUNET_CADET_Handle);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " addr %p\n", h);
+ h->cfg = cfg;
+ h->new_channel = new_channel;
+ h->cleaner = cleaner;
+ h->client = GNUNET_CLIENT_connect ("cadet", cfg);
+ if (h->client == NULL)
+ {
+ GNUNET_break (0);
+ GNUNET_free (h);
+ return NULL;
+ }
+ h->cls = cls;
+ h->message_handlers = handlers;
+ h->ports = ports;
+ h->next_chid = GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
+ h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
+ h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (NULL != ports && ports[0] != 0 && NULL == new_channel)
+ {
+ GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "no new channel handler given, ports parameter is useless!!\n");
+ }
+ if ((NULL == ports || ports[0] == 0) && NULL != new_channel)
+ {
+ GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "no ports given, new channel handler will never be called!!\n");
+ }
+ /* count handlers */
+ for (h->n_handlers = 0;
+ handlers && handlers[h->n_handlers].type;
+ h->n_handlers++) ;
+ for (h->n_ports = 0;
+ ports && ports[h->n_ports];
+ h->n_ports++) ;
+ send_connect (h);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_CADET_connect() END\n");
+ return h;
+}
+
+
+void
+GNUNET_CADET_disconnect (struct GNUNET_CADET_Handle *handle)
+{
+ struct GNUNET_CADET_Channel *ch;
+ struct GNUNET_CADET_Channel *aux;
+ struct GNUNET_CADET_TransmitHandle *th;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "CADET DISCONNECT\n");
+
+ ch = handle->channels_head;
+ while (NULL != ch)
+ {
+ aux = ch->next;
+ if (ch->chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV)
+ {
+ GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "channel %X not destroyed\n", ch->chid);
+ }
+ destroy_channel (ch, GNUNET_YES);
+ ch = aux;
+ }
+ while ( (th = handle->th_head) != NULL)
+ {
+ struct GNUNET_MessageHeader *msg;
+
+ /* Make sure it is an allowed packet (everything else should have been
+ * already canceled).
+ */
+ GNUNET_break (GNUNET_NO == th_is_payload (th));
+ msg = (struct GNUNET_MessageHeader *) &th[1];
+ switch (ntohs(msg->type))
+ {
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT:
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE:
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNELS:
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL:
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER:
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS:
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL:
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS:
+ break;
+ default:
+ GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_ERROR, "unexpected msg %u\n",
+ ntohs(msg->type));
+ }
+
+ GNUNET_CONTAINER_DLL_remove (handle->th_head, handle->th_tail, th);
+ GNUNET_free (th);
+ }
+
+ if (NULL != handle->th)
+ {
+ GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
+ handle->th = NULL;
+ }
+ if (NULL != handle->client)
+ {
+ GNUNET_CLIENT_disconnect (handle->client);
+ handle->client = NULL;
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task)
+ {
+ GNUNET_SCHEDULER_cancel(handle->reconnect_task);
+ handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_free (handle);
+}
+
+
+/**
+ * Create a new channel towards a remote peer.
+ *
+ * If the destination port is not open by any peer or the destination peer
+ * does not accept the channel, #GNUNET_CADET_ChannelEndHandler will be called
+ * for this channel.
+ *
+ * @param h cadet handle
+ * @param channel_ctx client's channel context to associate with the channel
+ * @param peer peer identity the channel should go to
+ * @param port Port number.
+ * @param options CadetOption flag field, with all desired option bits set to
1.
+ *
+ * @return handle to the channel
+ */
+struct GNUNET_CADET_Channel *
+GNUNET_CADET_channel_create (struct GNUNET_CADET_Handle *h,
+ void *channel_ctx,
+ const struct GNUNET_PeerIdentity *peer,
+ uint32_t port,
+ enum GNUNET_CADET_ChannelOption options)
+{
+ struct GNUNET_CADET_Channel *ch;
+ struct GNUNET_CADET_ChannelMessage msg;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating new channel to %s:%u\n",
+ GNUNET_i2s (peer), port);
+ ch = create_channel (h, 0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " at %p\n", ch);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " number %X\n", ch->chid);
+ ch->ctx = channel_ctx;
+ ch->peer = GNUNET_PEER_intern (peer);
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE);
+ msg.header.size = htons (sizeof (struct GNUNET_CADET_ChannelMessage));
+ msg.channel_id = htonl (ch->chid);
+ msg.port = htonl (port);
+ msg.peer = *peer;
+ msg.opt = htonl (options);
+ ch->allow_send = 0;
+ send_packet (h, &msg.header, ch);
+ return ch;
+}
+
+
+void
+GNUNET_CADET_channel_destroy (struct GNUNET_CADET_Channel *channel)
+{
+ struct GNUNET_CADET_Handle *h;
+ struct GNUNET_CADET_ChannelMessage msg;
+ struct GNUNET_CADET_TransmitHandle *th;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying channel\n");
+ h = channel->cadet;
+
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
+ msg.header.size = htons (sizeof (struct GNUNET_CADET_ChannelMessage));
+ msg.channel_id = htonl (channel->chid);
+ memset (&msg.peer, 0, sizeof (struct GNUNET_PeerIdentity));
+ msg.port = 0;
+ msg.opt = 0;
+ th = h->th_head;
+ while (th != NULL)
+ {
+ struct GNUNET_CADET_TransmitHandle *aux;
+ if (th->channel == channel)
+ {
+ aux = th->next;
+ /* FIXME call the handler? */
+ if (GNUNET_YES == th_is_payload (th))
+ th->notify (th->notify_cls, 0, NULL);
+ GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
+ GNUNET_free (th);
+ th = aux;
+ }
+ else
+ th = th->next;
+ }
+
+ destroy_channel (channel, GNUNET_YES);
+ send_packet (h, &msg.header, NULL);
+}
+
+
+/**
+ * Get information about a channel.
+ *
+ * @param channel Channel handle.
+ * @param option Query (GNUNET_CADET_OPTION_*).
+ * @param ... dependant on option, currently not used
+ *
+ * @return Union with an answer to the query.
+ */
+const union GNUNET_CADET_ChannelInfo *
+GNUNET_CADET_channel_get_info (struct GNUNET_CADET_Channel *channel,
+ enum GNUNET_CADET_ChannelOption option, ...)
+{
+ static int bool_flag;
+ const union GNUNET_CADET_ChannelInfo *ret;
+
+ switch (option)
+ {
+ case GNUNET_CADET_OPTION_NOBUFFER:
+ case GNUNET_CADET_OPTION_RELIABLE:
+ case GNUNET_CADET_OPTION_OOORDER:
+ if (0 != (option & channel->options))
+ bool_flag = GNUNET_YES;
+ else
+ bool_flag = GNUNET_NO;
+ ret = (const union GNUNET_CADET_ChannelInfo *) &bool_flag;
+ break;
+ case GNUNET_CADET_OPTION_PEER:
+ ret = (const union GNUNET_CADET_ChannelInfo *) GNUNET_PEER_resolve2
(channel->peer);
+ break;
+ default:
+ GNUNET_break (0);
+ return NULL;
+ }
+
+ return ret;
+}
+
+struct GNUNET_CADET_TransmitHandle *
+GNUNET_CADET_notify_transmit_ready (struct GNUNET_CADET_Channel *channel, int
cork,
+ struct GNUNET_TIME_Relative maxdelay,
+ size_t notify_size,
+ GNUNET_CONNECTION_TransmitReadyNotify
notify,
+ void *notify_cls)
+{
+ struct GNUNET_CADET_TransmitHandle *th;
+
+ GNUNET_assert (NULL != channel);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "CADET NOTIFY TRANSMIT READY\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X\n", channel->chid);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " allow_send %d\n", channel->allow_send);
+ if (channel->chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV)
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " to origin\n");
+ else
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " to destination\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " payload size %u\n", notify_size);
+ GNUNET_assert (NULL != notify);
+ GNUNET_assert (0 == channel->packet_size); // Only one data packet allowed
+ th = GNUNET_new (struct GNUNET_CADET_TransmitHandle);
+ th->channel = channel;
+ th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay);
+ th->size = notify_size + sizeof (struct GNUNET_CADET_LocalData);
+ channel->packet_size = th->size;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " total size %u\n", th->size);
+ th->notify = notify;
+ th->notify_cls = notify_cls;
+ add_to_queue (channel->cadet, th);
+ if (NULL != channel->cadet->th)
+ return th;
+ if (GNUNET_NO == channel->allow_send)
+ return th;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " call client notify tmt rdy\n");
+ channel->cadet->th =
+ GNUNET_CLIENT_notify_transmit_ready (channel->cadet->client, th->size,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_YES, &send_callback,
+ channel->cadet);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "CADET NOTIFY TRANSMIT READY END\n");
+ return th;
+}
+
+
+void
+GNUNET_CADET_notify_transmit_ready_cancel (struct GNUNET_CADET_TransmitHandle
*th)
+{
+ struct GNUNET_CADET_Handle *cadet;
+
+ th->channel->packet_size = 0;
+ cadet = th->channel->cadet;
+ if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (th->timeout_task);
+ GNUNET_CONTAINER_DLL_remove (cadet->th_head, cadet->th_tail, th);
+ GNUNET_free (th);
+ if ((0 == message_ready_size (cadet)) && (NULL != cadet->th))
+ {
+ /* queue empty, no point in asking for transmission */
+ GNUNET_CLIENT_notify_transmit_ready_cancel (cadet->th);
+ cadet->th = NULL;
+ }
+}
+
+
+void
+GNUNET_CADET_receive_done (struct GNUNET_CADET_Channel *channel)
+{
+ send_ack (channel);
+}
+
+
+static void
+send_info_request (struct GNUNET_CADET_Handle *h, uint16_t type)
+{
+ struct GNUNET_MessageHeader msg;
+
+ msg.size = htons (sizeof (msg));
+ msg.type = htons (type);
+ send_packet (h, &msg, NULL);
+}
+
+
+/**
+ * Request information about peers known to the running cadet service.
+ * The callback will be called for every peer known to the service.
+ * Only one info request (of any kind) can be active at once.
+ *
+ *
+ * WARNING: unstable API, likely to change in the future!
+ *
+ * @param h Handle to the cadet peer.
+ * @param callback Function to call with the requested data.
+ * @param callback_cls Closure for @c callback.
+ *
+ * @return #GNUNET_OK / #GNUNET_SYSERR
+ */
+int
+GNUNET_CADET_get_peers (struct GNUNET_CADET_Handle *h,
+ GNUNET_CADET_PeersCB callback,
+ void *callback_cls)
+{
+ if (NULL != h->info_cb.peers_cb)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ send_info_request (h, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
+ h->info_cb.peers_cb = callback;
+ h->info_cls = callback_cls;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Cancel a peer info request. The callback will not be called (anymore).
+ *
+ * WARNING: unstable API, likely to change in the future!
+ *
+ * @param h Cadet handle.
+ *
+ * @return Closure given to GNUNET_CADET_get_peers.
+ */
+void *
+GNUNET_CADET_get_peers_cancel (struct GNUNET_CADET_Handle *h)
+{
+ void *cls;
+
+ cls = h->info_cls;
+ h->info_cb.peers_cb = NULL;
+ h->info_cls = NULL;
+ return cls;
+}
+
+
+/**
+ * Request information about a peer known to the running cadet peer.
+ * The callback will be called for the tunnel once.
+ * Only one info request (of any kind) can be active at once.
+ *
+ * WARNING: unstable API, likely to change in the future!
+ *
+ * @param h Handle to the cadet peer.
+ * @param id Peer whose tunnel to examine.
+ * @param callback Function to call with the requested data.
+ * @param callback_cls Closure for @c callback.
+ *
+ * @return #GNUNET_OK / #GNUNET_SYSERR
+ */
+int
+GNUNET_CADET_get_peer (struct GNUNET_CADET_Handle *h,
+ const struct GNUNET_PeerIdentity *id,
+ GNUNET_CADET_PeerCB callback,
+ void *callback_cls)
+{
+ struct GNUNET_CADET_LocalInfo msg;
+
+ if (NULL != h->info_cb.peer_cb)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+
+ memset (&msg, 0, sizeof (msg));
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
+ msg.peer = *id;
+ send_packet (h, &msg.header, NULL);
+ h->info_cb.peer_cb = callback;
+ h->info_cls = callback_cls;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Request information about tunnels of the running cadet peer.
+ * The callback will be called for every tunnel of the service.
+ * Only one info request (of any kind) can be active at once.
+ *
+ * WARNING: unstable API, likely to change in the future!
+ *
+ * @param h Handle to the cadet peer.
+ * @param callback Function to call with the requested data.
+ * @param callback_cls Closure for @c callback.
+ *
+ * @return #GNUNET_OK / #GNUNET_SYSERR
+ */
+int
+GNUNET_CADET_get_tunnels (struct GNUNET_CADET_Handle *h,
+ GNUNET_CADET_TunnelsCB callback,
+ void *callback_cls)
+{
+ if (NULL != h->info_cb.tunnels_cb)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ send_info_request (h, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
+ h->info_cb.tunnels_cb = callback;
+ h->info_cls = callback_cls;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Cancel a monitor request. The monitor callback will not be called.
+ *
+ * @param h Cadet handle.
+ *
+ * @return Closure given to GNUNET_CADET_get_tunnels.
+ */
+void *
+GNUNET_CADET_get_tunnels_cancel (struct GNUNET_CADET_Handle *h)
+{
+ void *cls;
+
+ h->info_cb.tunnels_cb = NULL;
+ cls = h->info_cls;
+ h->info_cls = NULL;
+
+ return cls;
+}
+
+
+
+/**
+ * Request information about a tunnel of the running cadet peer.
+ * The callback will be called for the tunnel once.
+ * Only one info request (of any kind) can be active at once.
+ *
+ * WARNING: unstable API, likely to change in the future!
+ *
+ * @param h Handle to the cadet peer.
+ * @param id Peer whose tunnel to examine.
+ * @param callback Function to call with the requested data.
+ * @param callback_cls Closure for @c callback.
+ *
+ * @return #GNUNET_OK / #GNUNET_SYSERR
+ */
+int
+GNUNET_CADET_get_tunnel (struct GNUNET_CADET_Handle *h,
+ const struct GNUNET_PeerIdentity *id,
+ GNUNET_CADET_TunnelCB callback,
+ void *callback_cls)
+{
+ struct GNUNET_CADET_LocalInfo msg;
+
+ if (NULL != h->info_cb.tunnel_cb)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+
+ memset (&msg, 0, sizeof (msg));
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
+ msg.peer = *id;
+ send_packet (h, &msg.header, NULL);
+ h->info_cb.tunnel_cb = callback;
+ h->info_cls = callback_cls;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Request information about a specific channel of the running cadet peer.
+ *
+ * WARNING: unstable API, likely to change in the future!
+ * FIXME Add destination option.
+ *
+ * @param h Handle to the cadet peer.
+ * @param initiator ID of the owner of the channel.
+ * @param channel_number Channel number.
+ * @param callback Function to call with the requested data.
+ * @param callback_cls Closure for @c callback.
+ *
+ * @return #GNUNET_OK / #GNUNET_SYSERR
+ */
+int
+GNUNET_CADET_show_channel (struct GNUNET_CADET_Handle *h,
+ struct GNUNET_PeerIdentity *initiator,
+ unsigned int channel_number,
+ GNUNET_CADET_ChannelCB callback,
+ void *callback_cls)
+{
+ struct GNUNET_CADET_LocalInfo msg;
+
+ if (NULL != h->info_cb.channel_cb)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL);
+ msg.peer = *initiator;
+ msg.channel_id = htonl (channel_number);
+// msg.reserved = 0;
+ send_packet (h, &msg.header, NULL);
+ h->info_cb.channel_cb = callback;
+ h->info_cls = callback_cls;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called to notify a client about the connection
+ * begin ready to queue more data. "buf" will be
+ * NULL and "size" zero if the connection was closed for
+ * writing in the meantime.
+ *
+ * @param cls closure
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+static size_t
+cadet_mq_ntr (void *cls, size_t size,
+ void *buf)
+{
+ struct GNUNET_MQ_Handle *mq = cls;
+ struct CadetMQState *state = GNUNET_MQ_impl_state (mq);
+ const struct GNUNET_MessageHeader *msg = GNUNET_MQ_impl_current (mq);
+ uint16_t msize;
+
+ state->th = NULL;
+ if (NULL == buf)
+ {
+ GNUNET_MQ_inject_error (mq, GNUNET_MQ_ERROR_WRITE);
+ return 0;
+ }
+ msize = ntohs (msg->size);
+ GNUNET_assert (msize <= size);
+ memcpy (buf, msg, msize);
+ GNUNET_MQ_impl_send_continue (mq);
+ return msize;
+}
+
+
+/**
+ * Signature of functions implementing the
+ * sending functionality of a message queue.
+ *
+ * @param mq the message queue
+ * @param msg the message to send
+ * @param impl_state state of the implementation
+ */
+static void
+cadet_mq_send_impl (struct GNUNET_MQ_Handle *mq,
+ const struct GNUNET_MessageHeader *msg, void *impl_state)
+{
+ struct CadetMQState *state = impl_state;
+
+ GNUNET_assert (NULL == state->th);
+ state->th =
+ GNUNET_CADET_notify_transmit_ready (state->channel,
+ /* FIXME: add option for corking */
+ GNUNET_NO,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ ntohs (msg->size),
+ cadet_mq_ntr, mq);
+
+}
+
+
+/**
+ * Signature of functions implementing the
+ * destruction of a message queue.
+ * Implementations must not free 'mq', but should
+ * take care of 'impl_state'.
+ *
+ * @param mq the message queue to destroy
+ * @param impl_state state of the implementation
+ */
+static void
+cadet_mq_destroy_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
+{
+ struct CadetMQState *state = impl_state;
+
+ if (NULL != state->th)
+ GNUNET_CADET_notify_transmit_ready_cancel (state->th);
+
+ GNUNET_free (state);
+}
+
+
+/**
+ * Create a message queue for a cadet channel.
+ * The message queue can only be used to transmit messages,
+ * not to receive them.
+ *
+ * @param channel the channel to create the message qeue for
+ * @return a message queue to messages over the channel
+ */
+struct GNUNET_MQ_Handle *
+GNUNET_CADET_mq_create (struct GNUNET_CADET_Channel *channel)
+{
+ struct GNUNET_MQ_Handle *mq;
+ struct CadetMQState *state;
+
+ state = GNUNET_new (struct CadetMQState);
+ state->channel = channel;
+
+ mq = GNUNET_MQ_queue_for_callbacks (cadet_mq_send_impl,
+ cadet_mq_destroy_impl,
+ NULL, /* FIXME: cancel impl. */
+ state,
+ NULL, /* no msg handlers */
+ NULL, /* no err handlers */
+ NULL); /* no handler cls */
+ return mq;
+}
+
Copied: gnunet/src/cadet/cadet_common.c (from rev 33185,
gnunet/src/mesh/cadet_common.c)
===================================================================
--- gnunet/src/cadet/cadet_common.c (rev 0)
+++ gnunet/src/cadet/cadet_common.c 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,348 @@
+/*
+ This file is part of GNUnet.
+ (C) 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file cadet/cadet_common.c
+ * @brief CADET helper functions
+ * @author Bartlomiej Polot
+ */
+
+#include "cadet.h"
+
+/**
+ * @brief Translate a fwd variable into a string representation, for logging.
+ *
+ * @param fwd Is FWD? (#GNUNET_YES or #GNUNET_NO)
+ *
+ * @return String representing FWD or BCK.
+ */
+char *
+GM_f2s (int fwd)
+{
+ if (GNUNET_YES == fwd)
+ {
+ return "FWD";
+ }
+ else if (GNUNET_NO == fwd)
+ {
+ return "BCK";
+ }
+ else
+ {
+ /* Not an error, can happen with CONNECTION_BROKEN messages. */
+ return "";
+ }
+}
+
+int
+GM_is_pid_bigger (uint32_t bigger, uint32_t smaller)
+{
+ return (GNUNET_YES == PID_OVERFLOW (smaller, bigger) ||
+ (bigger > smaller && GNUNET_NO == PID_OVERFLOW (bigger, smaller)));
+}
+
+
+uint32_t
+GM_max_pid (uint32_t a, uint32_t b)
+{
+ if (GM_is_pid_bigger(a, b))
+ return a;
+ return b;
+}
+
+
+uint32_t
+GM_min_pid (uint32_t a, uint32_t b)
+{
+ if (GM_is_pid_bigger(a, b))
+ return b;
+ return a;
+}
+
+
+const struct GNUNET_HashCode *
+GM_h2hc (const struct GNUNET_CADET_Hash *id)
+{
+ static struct GNUNET_HashCode hc;
+ memcpy (&hc, id, sizeof (*id));
+
+ return &hc;
+}
+
+
+const char *
+GM_h2s (const struct GNUNET_CADET_Hash *id)
+{
+ static char s[53];
+
+ memcpy (s, GNUNET_h2s_full (GM_h2hc (id)), 52);
+ s[52] = '\0';
+
+ return s;
+}
+
+
+#if !defined(GNUNET_CULL_LOGGING)
+const char *
+GM_m2s (uint16_t m)
+{
+ static char buf[32];
+ const char *t;
+
+ switch (m)
+ {
+ /**
+ * Request the creation of a path
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
+ t = "CONNECTION_CREATE";
+ break;
+
+ /**
+ * Request the modification of an existing path
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK:
+ t = "CONNECTION_ACK";
+ break;
+
+ /**
+ * Notify that a connection of a path is no longer valid
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
+ t = "CONNECTION_BROKEN";
+ break;
+
+ /**
+ * At some point, the route will spontaneously change
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_PATH_CHANGED:
+ t = "PATH_CHANGED";
+ break;
+
+ /**
+ * Transport payload data.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_DATA:
+ t = "DATA";
+ break;
+
+ /**
+ * Confirm receipt of payload data.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK:
+ t = "DATA_ACK";
+ break;
+
+ /**
+ * Key exchange encapsulation.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_KX:
+ t = "KX";
+ break;
+
+ /**
+ * New ephemeral key.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL:
+ t = "KX_EPHEMERAL";
+ break;
+
+ /**
+ * Challenge to test peer's session key.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_KX_PING:
+ t = "KX_PING";
+ break;
+
+ /**
+ * Answer to session key challenge.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_KX_PONG:
+ t = "KX_PONG";
+ break;
+
+ /**
+ * Request the destuction of a path
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
+ t = "CONNECTION_DESTROY";
+ break;
+
+ /**
+ * ACK for a data packet.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_ACK:
+ t = "ACK";
+ break;
+
+ /**
+ * POLL for ACK.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_POLL:
+ t = "POLL";
+ break;
+
+ /**
+ * Announce origin is still alive.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE:
+ t = "KEEPALIVE";
+ break;
+
+ /**
+ * Connect to the cadet service, specifying subscriptions
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT:
+ t = "LOCAL_CONNECT";
+ break;
+
+ /**
+ * Ask the cadet service to create a new tunnel
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE:
+ t = "CHANNEL_CREATE";
+ break;
+
+ /**
+ * Ask the cadet service to destroy a tunnel
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
+ t = "CHANNEL_DESTROY";
+ break;
+
+ /**
+ * Confirm the creation of a channel.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK:
+ t = "CHANNEL_ACK";
+ break;
+
+ /**
+ * Confirm the creation of a channel.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK:
+ t = "CHANNEL_NACK";
+ break;
+
+ /**
+ * Encrypted payload.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
+ t = "ENCRYPTED";
+ break;
+
+ /**
+ * Local payload traffic
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA:
+ t = "LOCAL_DATA";
+ break;
+
+ /**
+ * Local ACK for data.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK:
+ t = "LOCAL_ACK";
+ break;
+
+ /**
+ * Local monitoring of channels.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNELS:
+ t = "LOCAL_INFO_CHANNELS";
+ break;
+
+ /**
+ * Local monitoring of a channel.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL:
+ t = "LOCAL_INFO_CHANNEL";
+ break;
+
+ /**
+ * Local monitoring of service.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS:
+ t = "LOCAL_INFO_TUNNELS";
+ break;
+
+ /**
+ * Local monitoring of service.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL:
+ t = "LOCAL_INFO_TUNNEL";
+ break;
+
+ /**
+ * Local information about all connections of service.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CONNECTIONS:
+ t = "LOCAL_INFO_CONNECTIONS";
+ break;
+
+ /**
+ * Local information of service about a specific connection.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CONNECTION:
+ t = "LOCAL_INFO_CONNECTION";
+ break;
+
+ /**
+ * Local information about all peers known to the service.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS:
+ t = "LOCAL_INFO_PEERS";
+ break;
+
+ /**
+ * Local information of service about a specific peer.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER:
+ t = "LOCAL_INFO_PEER";
+ break;
+
+ /**
+ * Traffic (net-cat style) used by the Command Line Interface.
+ */
+ case GNUNET_MESSAGE_TYPE_CADET_CLI:
+ t = "CLI";
+ break;
+
+ /**
+ * 640kb should be enough for everybody
+ */
+ case 299:
+ t = "RESERVE_END";
+ break;
+
+ default:
+ sprintf(buf, "%u (UNKNOWN TYPE)", m);
+ return buf;
+ }
+ sprintf(buf, "{%18s}", t);
+ return buf;
+}
+#else
+const char *
+GM_m2s (uint16_t m)
+{
+ return "";
+}
+#endif
Copied: gnunet/src/cadet/cadet_path.c (from rev 33185,
gnunet/src/mesh/cadet_path.c)
===================================================================
--- gnunet/src/cadet/cadet_path.c (rev 0)
+++ gnunet/src/cadet/cadet_path.c 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,213 @@
+/*
+ This file is part of GNUnet.
+ (C) 2001 - 2013 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file cadet/cadet_path.c
+ * @brief Path handling functions
+ * @author Bartlomiej Polot
+ */
+
+#include "cadet.h"
+#include "cadet_path.h"
+#include "gnunet-service-cadet_peer.h"
+
+/**
+ * @brief Destroy a path after some time has past.
+ *
+ * If the path is returned from DHT again after a while, try again.
+ *
+ * @param cls Closure (path to destroy).
+ * @param tc Task context.
+ */
+static void
+path_destroy_delayed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct CadetPeerPath *path = cls;
+ struct CadetPeer *peer;
+
+ path->path_delete = GNUNET_SCHEDULER_NO_TASK;
+ peer = GMP_get_short (path->peers[path->length - 1]);
+ GMP_remove_path (peer, path);
+}
+
+
+/**
+ * Create a new path
+ *
+ * @param length How many hops will the path have.
+ *
+ * @return A newly allocated path with a peer array of the specified length.
+ */
+struct CadetPeerPath *
+path_new (unsigned int length)
+{
+ struct CadetPeerPath *p;
+
+ p = GNUNET_new (struct CadetPeerPath);
+ if (length > 0)
+ {
+ p->length = length;
+ p->peers = GNUNET_malloc (length * sizeof (GNUNET_PEER_Id));
+ }
+ return p;
+}
+
+
+/**
+ * Invert the path
+ *
+ * @param path the path to invert
+ */
+void
+path_invert (struct CadetPeerPath *path)
+{
+ GNUNET_PEER_Id aux;
+ unsigned int i;
+
+ for (i = 0; i < path->length / 2; i++)
+ {
+ aux = path->peers[i];
+ path->peers[i] = path->peers[path->length - i - 1];
+ path->peers[path->length - i - 1] = aux;
+ }
+}
+
+
+/**
+ * Duplicate a path, incrementing short peer's rc.
+ *
+ * @param path The path to duplicate.
+ */
+struct CadetPeerPath *
+path_duplicate (const struct CadetPeerPath *path)
+{
+ struct CadetPeerPath *aux;
+ unsigned int i;
+
+ aux = path_new (path->length);
+ memcpy (aux->peers, path->peers, path->length * sizeof (GNUNET_PEER_Id));
+ for (i = 0; i < aux->length; i++)
+ GNUNET_PEER_change_rc (aux->peers[i], 1);
+ return aux;
+}
+
+
+/**
+ * Get the length of a path.
+ *
+ * @param path The path to measure, with the local peer at any point of it.
+ *
+ * @return Number of hops to reach destination.
+ * UINT_MAX in case the peer is not in the path.
+ */
+unsigned int
+path_get_length (struct CadetPeerPath *path)
+{
+ if (NULL == path)
+ return UINT_MAX;
+ return path->length;
+}
+
+
+
+/**
+ * Mark path as invalid: keep it aroud for a while to avoid trying it in a
loop.
+ *
+ * DHT_get sometimes returns bad cached results, for instance, on a locally
+ * cached result where the PUT followed a path that is no longer current.
+ *
+ * @param p Path to invalidate.
+ */
+void
+path_invalidate (struct CadetPeerPath *p)
+{
+ if (GNUNET_SCHEDULER_NO_TASK != p->path_delete)
+ return;
+
+ p->path_delete = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
+ &path_destroy_delayed, p);
+}
+
+
+/**
+ * Test if a path is valid (or at least not known to be invalid).
+ *
+ * @param path Path to test.
+ *
+ * @return #GNUNET_YES If the path is valid or unknown,
+ * #GNUNET_NO If the path is known to be invalid.
+ */
+int
+path_is_valid (const struct CadetPeerPath *path)
+{
+ return (GNUNET_SCHEDULER_NO_TASK == path->path_delete);
+}
+
+
+/**
+ * Destroy the path and free any allocated resources linked to it
+ *
+ * @param p the path to destroy
+ *
+ * @return GNUNET_OK on success
+ */
+int
+path_destroy (struct CadetPeerPath *p)
+{
+ if (NULL == p)
+ return GNUNET_OK;
+
+ GNUNET_PEER_decrement_rcs (p->peers, p->length);
+ GNUNET_free_non_null (p->peers);
+ if (GNUNET_SCHEDULER_NO_TASK != p->path_delete)
+ GNUNET_SCHEDULER_cancel (p->path_delete);
+ GNUNET_free (p);
+ return GNUNET_OK;
+}
+
+char *
+path_2s (struct CadetPeerPath *p)
+{
+ char *s;
+ char *old;
+ unsigned int i;
+
+ old = GNUNET_strdup ("");
+ for (i = 0; i < p->length; i++)
+ {
+ GNUNET_asprintf (&s, "%s %s",
+ old, GNUNET_i2s (GNUNET_PEER_resolve2 (p->peers[i])));
+ GNUNET_free_non_null (old);
+ old = s;
+ }
+ return s;
+}
+
+void
+path_debug (struct CadetPeerPath *p)
+{
+ unsigned int i;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "PATH:\n");
+ for (i = 0; i < p->length; i++)
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %s\n",
+ GNUNET_i2s (GNUNET_PEER_resolve2 (p->peers[i])));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "END\n");
+}
Copied: gnunet/src/cadet/cadet_path.h (from rev 33185,
gnunet/src/mesh/cadet_path.h)
===================================================================
--- gnunet/src/cadet/cadet_path.h (rev 0)
+++ gnunet/src/cadet/cadet_path.h 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,185 @@
+/*
+ This file is part of GNUnet.
+ (C) 2001 - 2013 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file cadet/cadet_path.h
+ * @brief Path handling functions
+ * @author Bartlomiej Polot
+ */
+
+#include "gnunet-service-cadet_connection.h"
+
+#ifndef CADET_PATH_H_
+#define CADET_PATH_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+ #if 0 /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+/******************************************************************************/
+/************************ DATA STRUCTURES
****************************/
+/******************************************************************************/
+
+/**
+ * Information regarding a possible path to reach a single peer
+ */
+struct CadetPeerPath
+{
+
+ /**
+ * Linked list
+ */
+ struct CadetPeerPath *next;
+ struct CadetPeerPath *prev;
+
+ /**
+ * List of all the peers that form the path from origin to target.
+ */
+ GNUNET_PEER_Id *peers;
+
+ /**
+ * Number of peers (hops) in the path
+ */
+ unsigned int length;
+
+ /**
+ * User defined data store.
+ */
+ struct CadetConnection *c;
+
+ /**
+ * Path's score, how reliable is the path.
+ */
+// int score;
+
+ /**
+ * Task to delete the path.
+ * We tried it, it didn't work, don't try again in a while.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier path_delete;
+
+};
+
+/******************************************************************************/
+/************************* FUNCTIONS
*****************************/
+/******************************************************************************/
+
+/**
+ * Create a new path.
+ *
+ * @param length How many hops will the path have.
+ *
+ * @return A newly allocated path with a peer array of the specified length.
+ */
+struct CadetPeerPath *
+path_new (unsigned int length);
+
+
+/**
+ * Invert the path.
+ *
+ * @param path The path to invert.
+ */
+void
+path_invert (struct CadetPeerPath *path);
+
+
+/**
+ * Duplicate a path, incrementing short peer's rc.
+ *
+ * @param path The path to duplicate.
+ */
+struct CadetPeerPath *
+path_duplicate (const struct CadetPeerPath *path);
+
+
+/**
+ * Get the length of a path.
+ *
+ * @param path The path to measure, with the local peer at any point of it.
+ *
+ * @return Number of hops to reach destination.
+ * UINT_MAX in case the peer is not in the path.
+ */
+unsigned int
+path_get_length (struct CadetPeerPath *path);
+
+/**
+ * Mark path as invalid: keep it aroud for a while to avoid trying it in a
loop.
+ *
+ * DHT_get sometimes returns bad cached results, for instance, on a locally
+ * cached result where the PUT followed a path that is no longer current.
+ *
+ * @param p Path to invalidate.
+ */
+void
+path_invalidate (struct CadetPeerPath *p);
+
+/**
+ * Test if a path is valid (or at least not known to be invalid).
+ *
+ * @param path Path to test.
+ *
+ * @return #GNUNET_YES If the path is valid or unknown,
+ * #GNUNET_NO If the path is known to be invalid.
+ */
+int
+path_is_valid (const struct CadetPeerPath *path);
+
+/**
+ * Destroy the path and free any allocated resources linked to it
+ *
+ * @param p the path to destroy
+ *
+ * @return GNUNET_OK on success
+ */
+int
+path_destroy (struct CadetPeerPath *p);
+
+/**
+ * Path -> allocated one line string. Caller must free.
+ *
+ * @param p Path.
+ */
+char *
+path_2s (struct CadetPeerPath *p);
+
+/**
+ * Print info about the path for debug.
+ *
+ * @param p Path to debug.
+ */
+void
+path_debug (struct CadetPeerPath *p);
+
+#if 0 /* keep Emacsens' auto-indent happy */
+{
+ #endif
+ #ifdef __cplusplus
+}
+#endif
+
+
+/* ifndef CADET_PATH_H */
+#endif
Copied: gnunet/src/cadet/cadet_protocol.h (from rev 33185,
gnunet/src/mesh/cadet_protocol.h)
===================================================================
--- gnunet/src/cadet/cadet_protocol.h (rev 0)
+++ gnunet/src/cadet/cadet_protocol.h 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,459 @@
+/*
+ This file is part of GNUnet.
+ (C) 2001 - 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @author Bartlomiej Polot
+ * @file cadet/cadet_protocol.h
+ */
+
+#ifndef CADET_PROTOCOL_H_
+#define CADET_PROTOCOL_H_
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "cadet.h"
+
+#ifdef __cplusplus
+
+struct GNUNET_CADET_TunnelMessage;
+extern "C"
+{
+#if 0
+ /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+/******************************************************************************/
+/******************** CADET NETWORK MESSAGES
**************************/
+/******************************************************************************/
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Message for cadet connection creation.
+ */
+struct GNUNET_CADET_ConnectionCreate
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE
+ *
+ * Size: sizeof (struct GNUNET_CADET_ConnectionCreate) +
+ * path_length * sizeof (struct GNUNET_PeerIdentity)
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * ID of the connection
+ */
+ struct GNUNET_CADET_Hash cid;
+
+ /**
+ * path_length structs defining the *whole* path from the origin [0] to the
+ * final destination [path_length-1].
+ */
+ /* struct GNUNET_PeerIdentity peers[path_length]; */
+};
+
+/**
+ * Message for ack'ing a connection
+ */
+struct GNUNET_CADET_ConnectionACK
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * ID of the connection.
+ */
+ struct GNUNET_CADET_Hash cid;
+
+};
+
+
+/**
+ * Message for encapsulation of a Key eXchange message in a connection.
+ */
+struct GNUNET_CADET_KX
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_CADET_KX.
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * ID of the connection.
+ */
+ struct GNUNET_CADET_Hash cid;
+
+ /* Specific KX message follows. */
+};
+
+
+/**
+ * Message transmitted with the signed ephemeral key of a peer. The
+ * session key is then derived from the two ephemeral keys (ECDHE).
+ *
+ * As far as possible, same as CORE's EphemeralKeyMessage.
+ */
+struct GNUNET_CADET_KX_Ephemeral
+{
+
+ /**
+ * Message type is GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL.
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Status of the sender (should be in "enum PeerStateMachine"), nbo.
+ */
+ int32_t sender_status GNUNET_PACKED;
+
+ /**
+ * An ECC signature of the 'origin' asserting the validity of
+ * the given ephemeral key.
+ */
+ struct GNUNET_CRYPTO_EddsaSignature signature;
+
+ /**
+ * Information about what is being signed.
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+ /**
+ * At what time was this key created (beginning of validity).
+ */
+ struct GNUNET_TIME_AbsoluteNBO creation_time;
+
+ /**
+ * When does the given ephemeral key expire (end of validity).
+ */
+ struct GNUNET_TIME_AbsoluteNBO expiration_time;
+
+ /**
+ * Ephemeral public ECC key (always for NIST P-521) encoded in a format
suitable
+ * for network transmission as created using 'gcry_sexp_sprint'.
+ */
+ struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
+
+ /**
+ * Public key of the signing peer (persistent version, not the ephemeral
public key).
+ */
+ struct GNUNET_PeerIdentity origin_identity;
+};
+
+
+/**
+ * We're sending an (encrypted) PING to the other peer to check if he
+ * can decrypt. The other peer should respond with a PONG with the
+ * same content, except this time encrypted with the receiver's key.
+ */
+struct GNUNET_CADET_KX_Ping
+{
+ /**
+ * Message type is GNUNET_MESSAGE_TYPE_CADET_KX_PING.
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Seed for the IV
+ */
+ uint32_t iv GNUNET_PACKED;
+
+ /**
+ * Intended target of the PING, used primarily to check
+ * that decryption actually worked.
+ */
+ struct GNUNET_PeerIdentity target;
+
+ /**
+ * Random number chosen to make reply harder.
+ */
+ uint32_t nonce GNUNET_PACKED;
+};
+
+
+/**
+ * Response to a PING. Includes data from the original PING.
+ */
+struct GNUNET_CADET_KX_Pong
+{
+ /**
+ * Message type is GNUNET_MESSAGE_TYPE_CADET_KX_PONG.
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Seed for the IV
+ */
+ uint32_t iv GNUNET_PACKED;
+
+ /**
+ * Same nonce as in the reve.
+ */
+ uint32_t nonce GNUNET_PACKED;
+};
+
+
+/**
+ * Tunnel(ed) message.
+ */
+struct GNUNET_CADET_Encrypted
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * ID of the connection.
+ */
+ struct GNUNET_CADET_Hash cid;
+
+ /**
+ * ID of the packet (hop by hop).
+ */
+ uint32_t pid GNUNET_PACKED;
+
+ /**
+ * Number of hops to live.
+ */
+ uint32_t ttl GNUNET_PACKED;
+
+ /**
+ * Initialization Vector for payload encryption.
+ */
+ uint32_t iv GNUNET_PACKED;
+
+ /**
+ * MAC of the encrypted message, used to verify message integrity.
+ * Everything after this value will be encrypted and authenticated.
+ */
+ struct GNUNET_CADET_Hash hmac;
+
+ /**
+ * Encrypted content follows.
+ */
+};
+
+
+/**
+ * Message to create a Channel.
+ */
+struct GNUNET_CADET_ChannelCreate
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * ID of the channel
+ */
+ CADET_ChannelNumber chid GNUNET_PACKED;
+
+ /**
+ * Destination port.
+ */
+ uint32_t port GNUNET_PACKED;
+
+ /**
+ * Channel options.
+ */
+ uint32_t opt GNUNET_PACKED;
+};
+
+
+/**
+ * Message to manage a Channel (ACK, NACK, Destroy).
+ */
+struct GNUNET_CADET_ChannelManage
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_CADET_CHANNEL_{ACK|NACK|DESTROY}
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * ID of the channel
+ */
+ CADET_ChannelNumber chid GNUNET_PACKED;
+};
+
+
+/**
+ * Message for cadet data traffic.
+ */
+struct GNUNET_CADET_Data
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_CADET_UNICAST,
+ * GNUNET_MESSAGE_TYPE_CADET_TO_ORIGIN
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Unique ID of the payload message
+ */
+ uint32_t mid GNUNET_PACKED;
+
+ /**
+ * ID of the channel
+ */
+ CADET_ChannelNumber chid GNUNET_PACKED;
+
+ /**
+ * Payload follows
+ */
+};
+
+
+/**
+ * Message to acknowledge end-to-end data.
+ */
+struct GNUNET_CADET_DataACK
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_CADET_DATA_ACK
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * ID of the channel
+ */
+ CADET_ChannelNumber chid GNUNET_PACKED;
+
+ /**
+ * Bitfield of already-received newer messages
+ * pid + 1 @ LSB
+ * pid + 64 @ MSB
+ */
+ uint64_t futures GNUNET_PACKED;
+
+ /**
+ * Last message ID received.
+ */
+ uint32_t mid GNUNET_PACKED;
+};
+
+
+/**
+ * Message to acknowledge cadet encrypted traffic.
+ */
+struct GNUNET_CADET_ACK
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_CADET_ACK
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Maximum packet ID authorized.
+ */
+ uint32_t ack GNUNET_PACKED;
+
+ /**
+ * ID of the connection.
+ */
+ struct GNUNET_CADET_Hash cid;
+};
+
+
+/**
+ * Message to query a peer about its Flow Control status regarding a tunnel.
+ */
+struct GNUNET_CADET_Poll
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_CADET_POLL
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Last packet sent.
+ */
+ uint32_t pid GNUNET_PACKED;
+
+ /**
+ * ID of the connection.
+ */
+ struct GNUNET_CADET_Hash cid;
+
+};
+
+
+/**
+ * Message for notifying a disconnection in a path
+ */
+struct GNUNET_CADET_ConnectionBroken
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * ID of the connection.
+ */
+ struct GNUNET_CADET_Hash cid;
+
+ /**
+ * ID of the endpoint
+ */
+ struct GNUNET_PeerIdentity peer1;
+
+ /**
+ * ID of the endpoint
+ */
+ struct GNUNET_PeerIdentity peer2;
+};
+
+
+/**
+ * Message to destroy a connection.
+ */
+struct GNUNET_CADET_ConnectionDestroy
+{
+ /**
+ * Type: GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * ID of the connection.
+ */
+ struct GNUNET_CADET_Hash cid;
+};
+
+
+GNUNET_NETWORK_STRUCT_END
+
+#if 0 /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* ifndef CADET_PROTOCOL_H */
+#endif
+/* end of cadet_protocol.h */
Copied: gnunet/src/cadet/cadet_test_lib.c (from rev 33185,
gnunet/src/mesh/cadet_test_lib.c)
===================================================================
--- gnunet/src/cadet/cadet_test_lib.c (rev 0)
+++ gnunet/src/cadet/cadet_test_lib.c 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,295 @@
+/*
+ This file is part of GNUnet.
+ (C) 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file cadet/cadet_test_lib.c
+ * @author Bartlomiej Polot
+ * @brief library for writing CADET tests
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "cadet_test_lib.h"
+#include "gnunet_cadet_service.h"
+
+/**
+ * Test context for a CADET Test.
+ */
+struct GNUNET_CADET_TEST_Context
+{
+ /**
+ * Array of running peers.
+ */
+ struct GNUNET_TESTBED_Peer **peers;
+
+ /**
+ * Array of handles to the CADET for each peer.
+ */
+ struct GNUNET_CADET_Handle **cadetes;
+
+ /**
+ * Operation associated with the connection to the CADET.
+ */
+ struct GNUNET_TESTBED_Operation **ops;
+
+ /**
+ * Main function of the test to run once all CADETs are available.
+ */
+ GNUNET_CADET_TEST_AppMain app_main;
+
+ /**
+ * Closure for 'app_main'.
+ */
+ void *app_main_cls;
+
+ /**
+ * Number of peers running, size of the arrays above.
+ */
+ unsigned int num_peers;
+
+ /**
+ * Handler for incoming tunnels.
+ */
+ GNUNET_CADET_InboundChannelNotificationHandler *new_channel;
+
+ /**
+ * Cleaner for destroyed incoming tunnels.
+ */
+ GNUNET_CADET_ChannelEndHandler *cleaner;
+
+ /**
+ * Message handlers.
+ */
+ struct GNUNET_CADET_MessageHandler* handlers;
+
+ /**
+ * Application ports.
+ */
+ const uint32_t *ports;
+
+};
+
+
+/**
+ * Context for a cadet adapter callback.
+ */
+struct GNUNET_CADET_TEST_AdapterContext
+{
+ /**
+ * Peer number for the particular peer.
+ */
+ unsigned int peer;
+
+ /**
+ * General context.
+ */
+ struct GNUNET_CADET_TEST_Context *ctx;
+};
+
+
+/**
+ * Adapter function called to establish a connection to
+ * the CADET service.
+ *
+ * @param cls closure
+ * @param cfg configuration of the peer to connect to; will be available until
+ * GNUNET_TESTBED_operation_done() is called on the operation returned
+ * from GNUNET_TESTBED_service_connect()
+ * @return service handle to return in 'op_result', NULL on error
+ */
+static void *
+cadet_connect_adapter (void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
+ struct GNUNET_CADET_TEST_Context *ctx = actx->ctx;
+ struct GNUNET_CADET_Handle *h;
+
+ h = GNUNET_CADET_connect (cfg,
+ (void *) (long) actx->peer,
+ ctx->new_channel,
+ ctx->cleaner,
+ ctx->handlers,
+ ctx->ports);
+ return h;
+}
+
+
+/**
+ * Adapter function called to destroy a connection to
+ * the CADET service.
+ *
+ * @param cls closure
+ * @param op_result service handle returned from the connect adapter
+ */
+static void
+cadet_disconnect_adapter (void *cls,
+ void *op_result)
+{
+ struct GNUNET_CADET_Handle *cadet = op_result;
+ struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
+
+ GNUNET_free (actx);
+ GNUNET_CADET_disconnect (cadet);
+}
+
+
+/**
+ * Callback to be called when a service connect operation is completed.
+ *
+ * @param cls The callback closure from functions generating an operation.
+ * @param op The operation that has been finished.
+ * @param ca_result The service handle returned from
+ * GNUNET_TESTBED_ConnectAdapter() (cadet handle).
+ * @param emsg Error message in case the operation has failed.
+ * NULL if operation has executed successfully.
+ */
+static void
+cadet_connect_cb (void *cls,
+ struct GNUNET_TESTBED_Operation *op,
+ void *ca_result,
+ const char *emsg)
+{
+ struct GNUNET_CADET_TEST_Context *ctx = cls;
+ unsigned int i;
+
+ if (NULL != emsg)
+ {
+ fprintf (stderr, "Failed to connect to CADET service: %s\n",
+ emsg);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ for (i = 0; i < ctx->num_peers; i++)
+ if (op == ctx->ops[i])
+ {
+ ctx->cadetes[i] = ca_result;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "...cadet %u connected\n", i);
+ }
+ for (i = 0; i < ctx->num_peers; i++)
+ if (NULL == ctx->cadetes[i])
+ return; /* still some CADET connections missing */
+ /* all CADET connections ready! */
+ ctx->app_main (ctx->app_main_cls,
+ ctx,
+ ctx->num_peers,
+ ctx->peers,
+ ctx->cadetes);
+}
+
+
+void
+GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx)
+{
+ unsigned int i;
+
+ for (i = 0; i < ctx->num_peers; i++)
+ {
+ GNUNET_assert (NULL != ctx->ops[i]);
+ GNUNET_TESTBED_operation_done (ctx->ops[i]);
+ ctx->ops[i] = NULL;
+ }
+ GNUNET_free (ctx->ops);
+ GNUNET_free (ctx->cadetes);
+ GNUNET_free (ctx);
+ GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
+ * Callback run when the testbed is ready (peers running and connected to
+ * each other)
+ *
+ * @param cls Closure (context).
+ * @param h the run handle
+ * @param num_peers Number of peers that are running.
+ * @param peers Handles to each one of the @c num_peers peers.
+ * @param links_succeeded the number of overlay link connection attempts that
+ * succeeded
+ * @param links_failed the number of overlay link connection attempts that
+ * failed
+ */
+static void
+cadet_test_run (void *cls,
+ struct GNUNET_TESTBED_RunHandle *h,
+ unsigned int num_peers,
+ struct GNUNET_TESTBED_Peer **peers,
+ unsigned int links_succeeded,
+ unsigned int links_failed)
+{
+ struct GNUNET_CADET_TEST_Context *ctx = cls;
+ unsigned int i;
+
+ if (num_peers != ctx->num_peers)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers started %u/%u, ending\n",
+ num_peers, ctx->num_peers);
+ exit (1);
+ }
+ ctx->peers = peers;
+ for (i = 0; i < num_peers; i++)
+ {
+ struct GNUNET_CADET_TEST_AdapterContext *newctx;
+ newctx = GNUNET_new (struct GNUNET_CADET_TEST_AdapterContext);
+ newctx->peer = i;
+ newctx->ctx = ctx;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting to cadet %u\n", i);
+ ctx->ops[i] = GNUNET_TESTBED_service_connect (ctx,
+ peers[i],
+ "cadet",
+ &cadet_connect_cb,
+ ctx,
+ &cadet_connect_adapter,
+ &cadet_disconnect_adapter,
+ newctx);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "op handle %p\n", ctx->ops[i]);
+ }
+}
+
+
+void
+GNUNET_CADET_TEST_run (const char *testname,
+ const char *cfgname,
+ unsigned int num_peers,
+ GNUNET_CADET_TEST_AppMain tmain,
+ void *tmain_cls,
+ GNUNET_CADET_InboundChannelNotificationHandler
new_channel,
+ GNUNET_CADET_ChannelEndHandler cleaner,
+ struct GNUNET_CADET_MessageHandler* handlers,
+ const uint32_t *ports)
+{
+ struct GNUNET_CADET_TEST_Context *ctx;
+
+ ctx = GNUNET_new (struct GNUNET_CADET_TEST_Context);
+ ctx->num_peers = num_peers;
+ ctx->ops = GNUNET_malloc (num_peers * sizeof (struct
GNUNET_TESTBED_Operation *));
+ ctx->cadetes = GNUNET_malloc (num_peers * sizeof (struct GNUNET_CADET_Handle
*));
+ ctx->app_main = tmain;
+ ctx->app_main_cls = tmain_cls;
+ ctx->new_channel = new_channel;
+ ctx->cleaner = cleaner;
+ ctx->handlers = handlers;
+ ctx->ports = ports;
+ GNUNET_TESTBED_test_run (testname,
+ cfgname,
+ num_peers,
+ 0LL, NULL, NULL,
+ &cadet_test_run, ctx);
+}
+
+/* end of cadet_test_lib.c */
Copied: gnunet/src/cadet/cadet_test_lib.h (from rev 33185,
gnunet/src/mesh/cadet_test_lib.h)
===================================================================
--- gnunet/src/cadet/cadet_test_lib.h (rev 0)
+++ gnunet/src/cadet/cadet_test_lib.h 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,106 @@
+/*
+ This file is part of GNUnet.
+ (C) 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file cadet/cadet_test_lib.h
+ * @author Bartlomiej Polot
+ * @brief library for writing CADET tests
+ */
+#ifndef CADET_TEST_LIB_H
+#define CADET_TEST_LIB_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0 /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include "gnunet_testbed_service.h"
+#include "gnunet_cadet_service.h"
+
+/**
+ * Test context for a CADET Test.
+ */
+struct GNUNET_CADET_TEST_Context;
+
+
+/**
+ * Main function of a CADET test.
+ *
+ * @param cls Closure.
+ * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
+ * @param num_peers Number of peers that are running.
+ * @param peers Array of peers.
+ * @param cadetes Handle to each of the CADETs of the peers.
+ */
+typedef void (*GNUNET_CADET_TEST_AppMain) (void *cls,
+ struct GNUNET_CADET_TEST_Context
*ctx,
+ unsigned int num_peers,
+ struct GNUNET_TESTBED_Peer **peers,
+ struct GNUNET_CADET_Handle
**cadetes);
+
+
+/**
+ * Run a test using the given name, configuration file and number of
+ * peers.
+ * All cadet callbacks will receive the peer number as the closure.
+ *
+ * @param testname Name of the test (for logging).
+ * @param cfgname Name of the configuration file.
+ * @param num_peers Number of peers to start.
+ * @param tmain Main function to run once the testbed is ready.
+ * @param tmain_cls Closure for 'tmain'.
+ * @param new_channel Handler for incoming tunnels.
+ * @param cleaner Cleaner for destroyed incoming tunnels.
+ * @param handlers Message handlers.
+ * @param ports Ports the peers offer.
+ */
+void
+GNUNET_CADET_TEST_run (const char *testname,
+ const char *cfgname,
+ unsigned int num_peers,
+ GNUNET_CADET_TEST_AppMain tmain,
+ void *tmain_cls,
+ GNUNET_CADET_InboundChannelNotificationHandler
new_channel,
+ GNUNET_CADET_ChannelEndHandler cleaner,
+ struct GNUNET_CADET_MessageHandler* handlers,
+ const uint32_t* ports);
+
+
+/**
+ * Clean up the testbed.
+ *
+ * @param ctx handle for the testbed
+ */
+void
+GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx);
+
+
+#if 0 /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+
+/* ifndef CADET_TEST_LIB_H */
+#endif
Copied: gnunet/src/cadet/cadet_tunnel_tree.c (from rev 33185,
gnunet/src/mesh/cadet_tunnel_tree.c)
===================================================================
--- gnunet/src/cadet/cadet_tunnel_tree.c (rev 0)
+++ gnunet/src/cadet/cadet_tunnel_tree.c 2014-05-07 12:07:16 UTC (rev
33186)
@@ -0,0 +1,1174 @@
+/*
+ This file is part of GNUnet.
+ (C) 2001 - 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file cadet/cadet_tunnel_tree.c
+ * @brief Tunnel tree handling functions
+ * @author Bartlomiej Polot
+ */
+
+#include "cadet.h"
+#include "cadet_tunnel_tree.h"
+
+#define CADET_TREE_DEBUG GNUNET_YES
+
+
+/**
+ * Node of path tree for a tunnel
+ */
+struct CadetTunnelTreeNode
+{
+ /**
+ * Peer this node describes
+ */
+ GNUNET_PEER_Id peer;
+
+ /**
+ * Parent node in the tree
+ */
+ struct CadetTunnelTreeNode *parent;
+
+ /**
+ * DLL of siblings
+ */
+ struct CadetTunnelTreeNode *next;
+
+ /**
+ * DLL of siblings
+ */
+ struct CadetTunnelTreeNode *prev;
+
+ /**
+ * DLL of children
+ */
+ struct CadetTunnelTreeNode *children_head;
+
+ /**
+ * DLL of children
+ */
+ struct CadetTunnelTreeNode *children_tail;
+
+ /**
+ * Status of the peer in the tunnel
+ */
+ enum CadetPeerState status;
+};
+
+
+/**
+ * Tree to reach all peers in the tunnel
+ */
+struct CadetTunnelTree
+{
+ /**
+ * Root node of peer tree
+ */
+ struct CadetTunnelTreeNode *root;
+
+ /**
+ * Node that represents our position in the tree (for non local tunnels)
+ */
+ struct CadetTunnelTreeNode *me;
+
+ /**
+ * DLL of disconneted nodes
+ */
+ struct CadetTunnelTreeNode *disconnected_head;
+
+ /**
+ * DLL of disconneted nodes
+ */
+ struct CadetTunnelTreeNode *disconnected_tail;
+
+ /**
+ * Cache of all peers and the first hop to them.
+ * Indexed by PeerIdentity, contains a pointer to the PeerIdentity
+ * of 1st hop.
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *first_hops;
+
+};
+
+
+/**
+ * Create a new path
+ *
+ * @param length How many hops will the path have.
+ *
+ * @return A newly allocated path with a peer array of the specified length.
+ */
+struct CadetPeerPath *
+path_new (unsigned int length)
+{
+ struct CadetPeerPath *p;
+
+ p = GNUNET_new (struct CadetPeerPath);
+ if (length > 0)
+ {
+ p->length = length;
+ p->peers = GNUNET_malloc (length * sizeof (GNUNET_PEER_Id));
+ }
+ return p;
+}
+
+
+/**
+ * Invert the path
+ *
+ * @param path the path to invert
+ */
+void
+path_invert (struct CadetPeerPath *path)
+{
+ GNUNET_PEER_Id aux;
+ unsigned int i;
+
+ for (i = 0; i < path->length / 2; i++)
+ {
+ aux = path->peers[i];
+ path->peers[i] = path->peers[path->length - i - 1];
+ path->peers[path->length - i - 1] = aux;
+ }
+}
+
+
+/**
+ * Duplicate a path, incrementing short peer's rc.
+ *
+ * @param path The path to duplicate.
+ */
+struct CadetPeerPath *
+path_duplicate (struct CadetPeerPath *path)
+{
+ struct CadetPeerPath *aux;
+ unsigned int i;
+
+ aux = path_new (path->length);
+ memcpy (aux->peers, path->peers, path->length * sizeof (GNUNET_PEER_Id));
+ for (i = 0; i < path->length; i++)
+ GNUNET_PEER_change_rc (path->peers[i], 1);
+ return aux;
+}
+
+
+/**
+ * Recusively update the info about what is the first hop to reach the node
+ *
+ * @param tree Tree this nodes belongs to.
+ * @param parent The node form which to start updating.
+ * @param hop If known, ID of the first hop.
+ * If not known, NULL to find out and pass on children.
+ */
+static void
+tree_node_update_first_hops (struct CadetTunnelTree *tree,
+ struct CadetTunnelTreeNode *parent,
+ struct GNUNET_PeerIdentity *hop);
+
+
+/**
+ * Get the length of a path.
+ *
+ * @param path The path to measure, with the local peer at any point of it.
+ *
+ * @return Number of hops to reach destination.
+ * UINT_MAX in case the peer is not in the path.
+ */
+unsigned int
+path_get_length (struct CadetPeerPath *path)
+{
+ if (NULL == path)
+ return UINT_MAX;
+ return path->length;
+}
+
+
+/**
+ * Destroy the path and free any allocated resources linked to it
+ *
+ * @param p the path to destroy
+ *
+ * @return GNUNET_OK on success
+ */
+int
+path_destroy (struct CadetPeerPath *p)
+{
+ if (NULL == p)
+ return GNUNET_OK;
+ GNUNET_PEER_decrement_rcs (p->peers, p->length);
+ GNUNET_free_non_null (p->peers);
+ GNUNET_free (p);
+ return GNUNET_OK;
+}
+
+
+
+/**
+ * Allocates and initializes a new node.
+ * Sets ID and parent of the new node and inserts it in the DLL of the parent
+ *
+ * @param parent Node that will be the parent from the new node, NULL for root
+ * @param peer Short Id of the new node
+ *
+ * @return Newly allocated node
+ */
+static struct CadetTunnelTreeNode *
+tree_node_new (struct CadetTunnelTreeNode *parent, GNUNET_PEER_Id peer)
+{
+ struct CadetTunnelTreeNode *node;
+
+ node = GNUNET_new (struct CadetTunnelTreeNode);
+ node->peer = peer;
+ GNUNET_PEER_change_rc (peer, 1);
+ node->parent = parent;
+ if (NULL != parent)
+ GNUNET_CONTAINER_DLL_insert (parent->children_head, parent->children_tail,
+ node);
+
+ return node;
+}
+
+
+/**
+ * Recursively find the given peer.
+ *
+ * @param parent Node where to start looking.
+ * @param peer_id Short ID of the peer to find.
+ *
+ * @return Pointer to the node of the peer. NULL if not found.
+ */
+static struct CadetTunnelTreeNode *
+tree_node_find_peer (struct CadetTunnelTreeNode *parent, GNUNET_PEER_Id
peer_id)
+{
+ struct CadetTunnelTreeNode *n;
+ struct CadetTunnelTreeNode *r;
+
+ if (parent->peer == peer_id)
+ return parent;
+ for (n = parent->children_head; NULL != n; n = n->next)
+ {
+ r = tree_node_find_peer (n, peer_id);
+ if (NULL != r)
+ return r;
+ }
+ return NULL;
+}
+
+
+/**
+ * Recusively update the info about what is the first hop to reach the node
+ *
+ * @param tree Tree this nodes belongs to.
+ * @param parent ID from node form which to start updating.
+ * @param hop If known, ID of the first hop.
+ * If not known, NULL to find out and pass on children.
+ */
+static void
+tree_node_update_first_hops (struct CadetTunnelTree *tree,
+ struct CadetTunnelTreeNode *parent,
+ struct GNUNET_PeerIdentity *hop)
+{
+ struct GNUNET_PeerIdentity pi;
+ struct GNUNET_PeerIdentity *copy;
+ struct GNUNET_PeerIdentity id;
+ struct CadetTunnelTreeNode *n;
+
+#if CADET_TREE_DEBUG
+ GNUNET_PEER_resolve (parent->peer, &id);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Finding first hop for %s.\n",
+ GNUNET_i2s (&id));
+#endif
+ if (NULL == hop)
+ {
+ struct CadetTunnelTreeNode *aux;
+ struct CadetTunnelTreeNode *old;
+
+ aux = old = parent;
+ while (aux != tree->me)
+ {
+#if CADET_TREE_DEBUG
+ GNUNET_PEER_resolve (aux->peer, &id);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: ... checking %s.\n",
+ GNUNET_i2s (&id));
+#endif
+ old = aux;
+ aux = aux->parent;
+ GNUNET_assert (NULL != aux);
+ }
+#if CADET_TREE_DEBUG
+ GNUNET_PEER_resolve (old->peer, &id);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: It's %s!\n",
+ GNUNET_i2s (&id));
+#endif
+ hop = π
+ GNUNET_PEER_resolve (old->peer, hop);
+ }
+ GNUNET_PEER_resolve (parent->peer, &id);
+ copy = GNUNET_CONTAINER_multihashmap_get (tree->first_hops, &id.hashPubKey);
+ if (NULL == copy)
+ copy = GNUNET_new (struct GNUNET_PeerIdentity);
+ *copy = *hop;
+
+ (void) GNUNET_CONTAINER_multihashmap_put (tree->first_hops, &id.hashPubKey,
+ copy,
+
GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
+
+ for (n = parent->children_head; NULL != n; n = n->next)
+ {
+ tree_node_update_first_hops (tree, n, hop);
+ }
+}
+
+
+static void
+tree_node_debug (struct CadetTunnelTreeNode *n, uint16_t level)
+{
+ struct CadetTunnelTreeNode *c;
+ struct GNUNET_PeerIdentity id;;
+ uint16_t i;
+
+ for (i = 0; i < level; i++)
+ FPRINTF (stderr, "%s", " ");
+ if (n->status == CADET_PEER_READY)
+ FPRINTF (stderr, "%s", "#");
+ if (n->status == CADET_PEER_SEARCHING)
+ FPRINTF (stderr, "%s", "+");
+ if (n->status == CADET_PEER_RELAY)
+ FPRINTF (stderr, "%s", "-");
+ if (n->status == CADET_PEER_RECONNECTING)
+ FPRINTF (stderr, "%s", "*");
+
+ GNUNET_PEER_resolve (n->peer, &id);
+ FPRINTF (stderr, "%s, [%u, %p] ", GNUNET_i2s (&id), n->peer, n);
+ if (NULL != n->parent)
+ {
+ GNUNET_PEER_resolve (n->parent->peer, &id);
+ FPRINTF (stderr, "(-> %s [%u])\n", GNUNET_i2s (&id), n->parent->peer);
+ }
+ else
+ FPRINTF (stderr, "%s", "(root)\n");
+ for (c = n->children_head; NULL != c; c = c->next)
+ tree_node_debug (c, level + 1);
+}
+
+
+/**
+ * Destroys and frees the node and all children
+ *
+ * @param parent Parent node to be destroyed
+ */
+static void
+tree_node_destroy (struct CadetTunnelTreeNode *parent)
+{
+ struct CadetTunnelTreeNode *n;
+ struct CadetTunnelTreeNode *next;
+
+ if (NULL == parent)
+ return;
+#if CADET_TREE_DEBUG
+ struct GNUNET_PeerIdentity id;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Destroying node %u\n",
+ parent->peer);
+ GNUNET_PEER_resolve (parent->peer, &id);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: (%s)\n", GNUNET_i2s (&id));
+#endif
+ n = parent->children_head;
+ while (NULL != n)
+ {
+ next = n->next;
+ tree_node_destroy (n);
+ n = next;
+ }
+ GNUNET_PEER_change_rc (parent->peer, -1);
+ if (NULL != parent->parent)
+ GNUNET_CONTAINER_DLL_remove (parent->parent->children_head,
+ parent->parent->children_tail, parent);
+ GNUNET_free (parent);
+}
+
+
+
+/**
+ * Create a new tree.
+ *
+ * @param peer A short peer id of the root of the tree.
+ *
+ * @return A newly allocated and initialized tunnel tree.
+ */
+struct CadetTunnelTree *
+tree_new (GNUNET_PEER_Id peer)
+{
+ struct CadetTunnelTree *tree;
+
+ tree = GNUNET_new (struct CadetTunnelTree);
+ tree->first_hops = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO);
+ tree->root = tree_node_new (NULL, peer);
+ tree->root->status = CADET_PEER_ROOT;
+
+ if (1 == peer)
+ {
+ tree->me = tree->root;
+ }
+
+ return tree;
+}
+
+
+/**
+ * Set the status of a node.
+ *
+ * @param tree Tree.
+ * @param peer A short peer id of the node.
+ * @param status New status to set.
+ */
+void
+tree_set_status (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer,
+ enum CadetPeerState status)
+{
+ struct CadetTunnelTreeNode *n;
+
+ n = tree_find_peer (tree, peer);
+ if (NULL == n)
+ return;
+ n->status = status;
+}
+
+
+/**
+ * Get the status of a node.
+ *
+ * @param tree Tree whose node's status we want to now.
+ * @param peer A short peer id of the node.
+ *
+ * @return Status of the peer.
+ */
+enum CadetPeerState
+tree_get_status (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer)
+{
+ struct CadetTunnelTreeNode *n;
+
+ n = tree_find_peer (tree, peer);
+ if (NULL == n)
+ return CADET_PEER_INVALID;
+ return n->status;
+}
+
+
+/**
+ * Get the id of the predecessor of the local node.
+ *
+ * @param tree Tree whose local id we want to now.
+ *
+ * @return Short peer id of local peer.
+ */
+GNUNET_PEER_Id
+tree_get_predecessor (struct CadetTunnelTree *tree)
+{
+ if (NULL != tree->me && NULL != tree->me->parent)
+ return tree->me->parent->peer;
+ else
+ return (GNUNET_PEER_Id) 0;
+}
+
+
+/**
+ * Find the first peer whom to send a packet to go down this path
+ *
+ * @param t The tunnel tree to use
+ * @param peer The peerinfo of the peer we are trying to reach
+ *
+ * @return peerinfo of the peer who is the first hop in the tunnel
+ * NULL on error
+ *
+ * FIXME use PEER_Id
+ */
+struct GNUNET_PeerIdentity *
+tree_get_first_hop (struct CadetTunnelTree *t, GNUNET_PEER_Id peer)
+{
+ struct GNUNET_PeerIdentity id;
+ struct GNUNET_PeerIdentity *r;
+
+ GNUNET_PEER_resolve (peer, &id);
+ r = GNUNET_CONTAINER_multihashmap_get (t->first_hops, &id.hashPubKey);
+ if (NULL == r)
+ {
+ struct CadetTunnelTreeNode *n;
+
+ n = tree_find_peer (t, peer);
+ if (NULL != t->me && NULL != n)
+ {
+ tree_node_update_first_hops (t, n, NULL);
+ r = GNUNET_CONTAINER_multihashmap_get (t->first_hops, &id.hashPubKey);
+ GNUNET_assert (NULL != r);
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Tree structure inconsistent! me: %p, n: %p", t->me, n);
+ GNUNET_break (0);
+ }
+ }
+
+ return r;
+}
+
+
+/**
+ * Find the given peer in the tree.
+ *
+ * @param tree Tree where to look for the peer.
+ * @param peer_id Short ID of the peer to find.
+ *
+ * @return Pointer to the node of the peer. NULL if not found.
+ */
+struct CadetTunnelTreeNode *
+tree_find_peer (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer_id)
+{
+ return tree_node_find_peer (tree->root, peer_id);
+}
+
+
+/**
+ * Recusively mark peer and children as disconnected, notify client
+ *
+ * @param tree Tree this node belongs to
+ * @param parent Node to be clean, potentially with children
+ * @param cb Callback to use to notify about disconnected peers.
+ * @param cbcls Closure for cb.
+ */
+static void
+tree_mark_peers_disconnected (struct CadetTunnelTree *tree,
+ struct CadetTunnelTreeNode *parent,
+ CadetTreeCallback cb, void *cbcls)
+{
+ struct GNUNET_PeerIdentity *pi;
+ struct GNUNET_PeerIdentity id;
+ struct CadetTunnelTreeNode *n;
+
+ for (n = parent->children_head; NULL != n; n = n->next)
+ {
+ tree_mark_peers_disconnected (tree, n, cb, cbcls);
+ }
+ if (CADET_PEER_READY == parent->status)
+ {
+ if (NULL != cb)
+ cb (cbcls, parent->peer);
+ parent->status = CADET_PEER_RECONNECTING;
+ }
+
+ /* Remove and free info about first hop */
+ GNUNET_PEER_resolve (parent->peer, &id);
+ pi = GNUNET_CONTAINER_multihashmap_get (tree->first_hops, &id.hashPubKey);
+ GNUNET_CONTAINER_multihashmap_remove_all (tree->first_hops, &id.hashPubKey);
+ if (NULL != pi)
+ GNUNET_free (pi);
+}
+
+
+/**
+ * Iterate over all children of the local node.
+ *
+ * @param tree Tree to use. Must have "me" set.
+ * @param cb Callback to call over each child.
+ * @param cb_cls Closure for @c cb.
+ */
+void
+tree_iterate_children (struct CadetTunnelTree *tree, CadetTreeCallback cb,
+ void *cb_cls)
+{
+ struct CadetTunnelTreeNode *n;
+
+ if (NULL == tree->me)
+ return;
+ for (n = tree->me->children_head; NULL != n; n = n->next)
+ {
+ cb (cb_cls, n->peer);
+ }
+}
+
+
+/**
+ * Struct to contain a list of pending nodes when iterating a tree.
+ */
+struct CadetTreePendingNode {
+
+ /**
+ * DLL next.
+ */
+ struct CadetTreePendingNode *next;
+
+ /**
+ * DLL prev.
+ */
+ struct CadetTreePendingNode *prev;
+
+ /**
+ * Pending node.
+ */
+ struct CadetTunnelTreeNode *node;
+};
+
+
+/**
+ * Iterate over all nodes in the tree.
+ *
+ * @param tree Tree to use..
+ * @param cb Callback to call over each child.
+ * @param cb_cls Closure for @c cb.
+ *
+ * TODO: recursive implementation? (s/heap/stack/g)
+ */
+void
+tree_iterate_all (struct CadetTunnelTree *tree,
+ CadetWholeTreeCallback cb,
+ void *cb_cls)
+{
+ struct CadetTunnelTreeNode *parent;
+ struct CadetTunnelTreeNode *n;
+ struct CadetTreePendingNode *head;
+ struct CadetTreePendingNode *tail;
+ struct CadetTreePendingNode *pending;
+
+ cb (cb_cls, tree->root->peer, 0);
+ pending = GNUNET_new (struct CadetTreePendingNode);
+ pending->node = tree->root;
+ head = tail = NULL;
+ GNUNET_CONTAINER_DLL_insert (head, tail, pending);
+
+ while (NULL != head)
+ {
+ pending = head;
+ parent = pending->node;
+ GNUNET_CONTAINER_DLL_remove (head, tail, pending);
+ GNUNET_free (pending);
+ for (n = parent->children_head; NULL != n; n = n->next)
+ {
+ cb (cb_cls, n->peer, parent->peer);
+ pending = GNUNET_new (struct CadetTreePendingNode);
+ pending->node = n;
+ /* Insert_tail: breadth first, Insert: depth first */
+ GNUNET_CONTAINER_DLL_insert (head, tail, pending);
+ }
+ }
+}
+
+
+/**
+ * Iterator to count the children in a tree.
+ */
+static void
+count_children_cb (void *cls, GNUNET_PEER_Id peer)
+{
+ unsigned int *i = cls;
+
+ (*i)++;
+}
+
+
+/**
+ * Count how many children does the local node have in the tree.
+ *
+ * @param tree Tree to use. Must have "me" set.
+ */
+unsigned int
+tree_count_children (struct CadetTunnelTree *tree)
+{
+ unsigned int i;
+
+ i = 0;
+ tree_iterate_children(tree, &count_children_cb, &i);
+ return i;
+}
+
+
+/**
+ * Recusively update the info about what is the first hop to reach the node
+ *
+ * @param tree Tree this nodes belongs to.
+ * @param parent_id Short ID from node form which to start updating.
+ * @param hop If known, ID of the first hop.
+ * If not known, NULL to find out and pass on children.
+ */
+void
+tree_update_first_hops (struct CadetTunnelTree *tree, GNUNET_PEER_Id parent_id,
+ struct GNUNET_PeerIdentity *hop)
+{
+ tree_node_update_first_hops (tree, tree_find_peer (tree, parent_id), hop);
+}
+
+
+/**
+ * Delete the current path to the peer, including all now unused relays.
+ * The destination peer is NOT destroyed, it is returned in order to either set
+ * a new path to it or destroy it explicitly, taking care of it's child nodes.
+ *
+ * @param t Tunnel tree where to delete the path from.
+ * @param peer_id Short ID of the destination peer whose path we want to
remove.
+ * @param cb Callback to use to notify about disconnected peers.
+ * @param cbcls Closure for cb.
+ *
+ * @return pointer to the pathless node.
+ * NULL when not found
+ */
+struct CadetTunnelTreeNode *
+tree_del_path (struct CadetTunnelTree *t, GNUNET_PEER_Id peer_id,
+ CadetTreeCallback cb, void *cbcls)
+{
+ struct CadetTunnelTreeNode *parent;
+ struct CadetTunnelTreeNode *node;
+ struct CadetTunnelTreeNode *n;
+
+#if CADET_TREE_DEBUG
+ struct GNUNET_PeerIdentity id;
+
+ GNUNET_PEER_resolve (peer_id, &id);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Deleting path to %s.\n",
+ GNUNET_i2s (&id));
+#endif
+ if (NULL == t->root || peer_id == t->root->peer)
+ return NULL;
+
+ for (n = t->disconnected_head; NULL != n; n = n->next)
+ {
+ if (n->peer == peer_id)
+ {
+ /* Was already pathless, waiting for reconnection */
+ GNUNET_CONTAINER_DLL_remove (t->disconnected_head, t->disconnected_tail,
+ n);
+ return n;
+ }
+ }
+ n = tree_find_peer (t, peer_id);
+ if (NULL == n)
+ return NULL;
+ node = n;
+
+ parent = n->parent;
+ GNUNET_CONTAINER_DLL_remove (parent->children_head, parent->children_tail,
n);
+ n->parent = NULL;
+
+ while (CADET_PEER_RELAY == parent->status &&
+ NULL == parent->children_head)
+ {
+#if CADET_TREE_DEBUG
+ GNUNET_PEER_resolve (parent->peer, &id);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Deleting node %s.\n",
+ GNUNET_i2s (&id));
+#endif
+ n = parent->parent;
+ if (parent == t->me)
+ t->me = NULL;
+ tree_node_destroy (parent);
+ parent = n;
+ }
+#if CADET_TREE_DEBUG
+ GNUNET_PEER_resolve (parent->peer, &id);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Not deleted peer %s.\n",
+ GNUNET_i2s (&id));
+#endif
+
+ tree_mark_peers_disconnected (t, node, cb, cbcls);
+
+ return node;
+}
+
+
+/**
+ * Return a newly allocated individual path to reach a peer from the local
peer,
+ * according to the path tree of some tunnel.
+ *
+ * @param t Tunnel from which to read the path tree.
+ * @param peer Short ID of the destination peer to whom we want a path.
+ *
+ * @return A newly allocated individual path to reach the destination peer.
+ * Path must be destroyed afterwards.
+ */
+struct CadetPeerPath *
+tree_get_path_to_peer (struct CadetTunnelTree *t, GNUNET_PEER_Id peer)
+{
+ struct CadetTunnelTreeNode *n;
+ struct CadetPeerPath *p;
+
+ n = tree_find_peer (t, peer);
+ if (NULL == n)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ p = path_new (0);
+
+ /* Building the path (inverted!) */
+ while (n->peer != 1)
+ {
+ GNUNET_array_append (p->peers, p->length, n->peer);
+ GNUNET_PEER_change_rc (n->peer, 1);
+ n = n->parent;
+ if (NULL == n)
+ {
+ GNUNET_break (0);
+ path_destroy (p);
+ return NULL;
+ }
+ }
+ GNUNET_array_append (p->peers, p->length, 1);
+ GNUNET_PEER_change_rc (1, 1);
+
+ path_invert (p);
+
+ return p;
+}
+
+
+
+/**
+ * Integrate a stand alone path into the tunnel tree.
+ * If the peer toward which the new path is already in the tree, the peer
+ * and its children will be maked as disconnected and the callback
+ * will be called on each one of them. They will be maked as online only after
+ * receiving a PATH ACK for the new path for each one of them, so the caller
+ * should take care of sending a new CREATE PATH message for each disconnected
+ * peer.
+ *
+ * @param t Tunnel where to add the new path.
+ * @param p Path to be integrated.
+ * @param cb Callback to use to notify about peers temporarily disconnecting.
+ * @param cbcls Closure for cb.
+ *
+ * @return GNUNET_OK in case of success.
+ * GNUNET_SYSERR in case of error.
+ *
+ * TODO: optimize
+ * - go backwards on path looking for each peer in the present tree
+ * - do not disconnect peers until new path is created & connected
+ */
+int
+tree_add_path (struct CadetTunnelTree *t, const struct CadetPeerPath *p,
+ CadetTreeCallback cb, void *cbcls)
+{
+ struct CadetTunnelTreeNode *parent;
+ struct CadetTunnelTreeNode *oldnode;
+ struct CadetTunnelTreeNode *n;
+ struct CadetTunnelTreeNode *c;
+ struct GNUNET_PeerIdentity id;
+ int me;
+ unsigned int i;
+
+#if CADET_TREE_DEBUG
+ GNUNET_PEER_resolve (p->peers[p->length - 1], &id);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "tree: Adding path [%u] towards peer %s.\n", p->length,
+ GNUNET_i2s (&id));
+#endif
+
+ GNUNET_assert (0 != p->length);
+ parent = n = t->root;
+ if (n->peer != p->peers[0])
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (1 == p->length)
+ return GNUNET_OK;
+ oldnode = tree_del_path (t, p->peers[p->length - 1], cb, cbcls);
+ /* Look for the first node that is not already present in the tree
+ *
+ * Assuming that the tree is somewhat balanced, O(log n * log N).
+ * - Length of the path is expected to be log N (size of whole network).
+ * - Each level of the tree is expected to have log n children (size of
tree).
+ */
+ me = t->root->peer == 1 ? 0 : -1;
+ for (i = 1; i < p->length; i++)
+ {
+#if CADET_TREE_DEBUG
+ GNUNET_PEER_resolve (p->peers[i], &id);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Looking for peer %s.\n",
+ GNUNET_i2s (&id));
+#endif
+ parent = n;
+ if (p->peers[i] == 1)
+ me = i;
+ for (c = n->children_head; NULL != c; c = c->next)
+ {
+ if (c->peer == p->peers[i])
+ {
+#if CADET_TREE_DEBUG
+ GNUNET_PEER_resolve (parent->peer, &id);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "tree: Found in children of %s.\n", GNUNET_i2s (&id));
+#endif
+ n = c;
+ break;
+ }
+ }
+ /* If we couldn't find a child equal to path[i], we have reached the end
+ * of the common path. */
+ if (parent == n)
+ break;
+ }
+#if CADET_TREE_DEBUG
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: All childen visited.\n");
+#endif
+ /* Add the rest of the path as a branch from parent. */
+ while (i < p->length)
+ {
+#if CADET_TREE_DEBUG
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Adding peer %u to %u.\n",
+ p->peers[i], parent->peer);
+ GNUNET_PEER_resolve (p->peers[i], &id);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Adding peer %s.\n",
+ GNUNET_i2s (&id));
+ GNUNET_PEER_resolve (parent->peer, &id);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: to %s.\n",
+ GNUNET_i2s (&id));
+#endif
+
+ if (i == p->length - 1 && NULL != oldnode)
+ {
+#if CADET_TREE_DEBUG
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "tree: Putting old node into place.\n");
+#endif
+ oldnode->parent = parent;
+ GNUNET_CONTAINER_DLL_insert (parent->children_head,
parent->children_tail,
+ oldnode);
+ tree_node_update_first_hops (t, oldnode, NULL);
+ n = oldnode;
+ }
+ else
+ {
+#if CADET_TREE_DEBUG
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Creating new node.\n");
+#endif
+ n = tree_node_new (parent, p->peers[i]);
+ n->status = CADET_PEER_RELAY;
+ }
+ if (n->peer == 1)
+ {
+ t->me = n;
+ me = i;
+ }
+ i++;
+ parent = n;
+ }
+ n->status = CADET_PEER_SEARCHING;
+
+ GNUNET_break (-1 != me);
+
+ /* Add info about first hop into hashmap. */
+ if (-1 != me && me < p->length - 1)
+ {
+#if CADET_TREE_DEBUG
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "CADET: finding first hop (own pos %d/%u)\n", me,
+ p->length - 1);
+#endif
+ GNUNET_PEER_resolve (p->peers[me + 1], &id);
+ tree_update_first_hops (t, p->peers[me + 1], &id);
+ }
+#if CADET_TREE_DEBUG
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "CADET: was last in path, not updating first hops (%d/%u)\n",
+ me, p->length - 1);
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: New node added.\n");
+#endif
+ if (NULL == t->me)
+ t->me = tree_find_peer (t, 1);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Notifies a tree that a connection it might be using is broken.
+ * Marks all peers down the paths as disconnected and notifies the client.
+ *
+ * @param t Tree to use.
+ * @param p1 Short id of one of the peers (order unimportant)
+ * @param p2 Short id of one of the peers (order unimportant)
+ * @param cb Function to call for every peer that is marked as disconnected.
+ * @param cbcls Closure for cb.
+ *
+ * @return Short ID of the first disconnected peer in the tree.
+ */
+GNUNET_PEER_Id
+tree_notify_connection_broken (struct CadetTunnelTree *t, GNUNET_PEER_Id p1,
+ GNUNET_PEER_Id p2, CadetTreeCallback cb,
+ void *cbcls)
+{
+ struct CadetTunnelTreeNode *n;
+ struct CadetTunnelTreeNode *c;
+
+ n = tree_find_peer (t, p1);
+ if (NULL == n)
+ return 0;
+ if (NULL != n->parent && n->parent->peer == p2)
+ {
+ tree_mark_peers_disconnected (t, n, cb, cbcls);
+ GNUNET_CONTAINER_DLL_remove (n->parent->children_head,
+ n->parent->children_tail, n);
+ GNUNET_CONTAINER_DLL_insert (t->disconnected_head, t->disconnected_tail,
n);
+ return p1;
+ }
+ for (c = n->children_head; NULL != c; c = c->next)
+ {
+ if (c->peer == p2)
+ {
+ tree_mark_peers_disconnected (t, c, cb, cbcls);
+ GNUNET_CONTAINER_DLL_remove (n->children_head, n->children_tail, c);
+ GNUNET_CONTAINER_DLL_insert (t->disconnected_head, t->disconnected_tail,
+ c);
+ return p2;
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * Deletes a peer from a tunnel, liberating all unused resources on the path to
+ * it. It shouldn't have children, if it has they will be destroyed as well.
+ * If the tree is not local and no longer has any paths, the root node will be
+ * destroyed and marked as NULL.
+ *
+ * @param t Tunnel tree to use.
+ * @param peer Short ID of the peer to remove from the tunnel tree.
+ * @param cb Callback to notify client of disconnected peers.
+ * @param cbcls Closure for cb.
+ *
+ * @return GNUNET_OK or GNUNET_SYSERR
+ */
+int
+tree_del_peer (struct CadetTunnelTree *t, GNUNET_PEER_Id peer,
+ CadetTreeCallback cb, void *cbcls)
+{
+ struct CadetTunnelTreeNode *n;
+
+ n = tree_del_path (t, peer, cb, cbcls);
+ if (NULL == n)
+ {
+ GNUNET_break (0);
+ return GNUNET_YES;
+ }
+ tree_node_destroy (n);
+ if (NULL == t->root->children_head && t->me != t->root)
+ {
+ tree_node_destroy (t->root);
+ t->root = NULL;
+ return GNUNET_NO;
+ }
+ return GNUNET_YES;
+}
+
+
+
+/**
+ * Get the cost of the path relative to the already built tunnel tree.
+ *
+ * @param t The tunnel tree to which compare.
+ * @param path The individual path to reach a peer. It has to start at the
+ * root of the tree to be comparable.
+ *
+ * @return Number of hops to reach destination, UINT_MAX in case the peer is
not
+ * in the path.
+ *
+ * TODO: adapt to allow any start / root combination
+ * TODO: take in account state of the nodes
+ */
+unsigned int
+tree_get_path_cost (struct CadetTunnelTree *t, struct CadetPeerPath *path)
+{
+ struct CadetTunnelTreeNode *n;
+ struct CadetTunnelTreeNode *p;
+ unsigned int i;
+ unsigned int l;
+
+ l = path_get_length (path);
+ p = t->root;
+ if (t->root->peer != path->peers[0])
+ {
+ GNUNET_break (0);
+ return UINT_MAX;
+ }
+ for (i = 1; i < l; i++)
+ {
+ for (n = p->children_head; NULL != n; n = n->next)
+ {
+ if (path->peers[i] == n->peer)
+ {
+ break;
+ }
+ }
+ if (NULL == n)
+ return l - i;
+ p = n;
+ }
+ return l - i;
+}
+
+
+/**
+ * Print the tree on stderr
+ *
+ * @param t The tree
+ */
+void
+tree_debug (struct CadetTunnelTree *t)
+{
+ tree_node_debug (t->root, 0);
+ FPRINTF (stderr, "root: %p\n", t->root);
+ FPRINTF (stderr, "me: %p\n", t->me);
+}
+
+
+/**
+ * Iterator over hash map peer entries and frees all data in it.
+ * Used prior to destroying a hashmap. Makes you miss anonymous functions in C.
+ *
+ * @param cls closure
+ * @param key current key code (will no longer contain valid data!!)
+ * @param value value in the hash map (treated as void *)
+ * @return GNUNET_YES if we should continue to iterate, GNUNET_NO if not.
+ */
+static int
+iterate_free (void *cls, const struct GNUNET_HashCode * key, void *value)
+{
+ GNUNET_free (value);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Destroy the whole tree and free all used memory and Peer_Ids
+ *
+ * @param t Tree to be destroyed
+ */
+void
+tree_destroy (struct CadetTunnelTree *t)
+{
+#if CADET_TREE_DEBUG
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Destroying tree\n");
+#endif
+ tree_node_destroy (t->root);
+ GNUNET_CONTAINER_multihashmap_iterate (t->first_hops, &iterate_free, NULL);
+ GNUNET_CONTAINER_multihashmap_destroy (t->first_hops);
+ GNUNET_free (t);
+}
Copied: gnunet/src/cadet/cadet_tunnel_tree.h (from rev 33185,
gnunet/src/mesh/cadet_tunnel_tree.h)
===================================================================
--- gnunet/src/cadet/cadet_tunnel_tree.h (rev 0)
+++ gnunet/src/cadet/cadet_tunnel_tree.h 2014-05-07 12:07:16 UTC (rev
33186)
@@ -0,0 +1,382 @@
+/*
+ This file is part of GNUnet.
+ (C) 2001 - 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file cadet/cadet_tunnel_tree.h
+ * @brief Tunnel tree handling functions
+ * @author Bartlomiej Polot
+ */
+
+#include "cadet.h"
+
+/******************************************************************************/
+/************************ DATA STRUCTURES
****************************/
+/******************************************************************************/
+
+/**
+ * Information regarding a possible path to reach a single peer
+ */
+struct CadetPeerPath
+{
+
+ /**
+ * Linked list
+ */
+ struct CadetPeerPath *next;
+ struct CadetPeerPath *prev;
+
+ /**
+ * List of all the peers that form the path from origin to target.
+ */
+ GNUNET_PEER_Id *peers;
+
+ /**
+ * Number of peers (hops) in the path
+ */
+ unsigned int length;
+
+};
+
+
+/**
+ * Node of path tree for a tunnel
+ */
+struct CadetTunnelTreeNode;
+
+
+/**
+ * Tree to reach all peers in the tunnel
+ */
+struct CadetTunnelTree;
+
+
+/******************************************************************************/
+/************************* FUNCTIONS
*****************************/
+/******************************************************************************/
+
+/**
+ * Create a new path.
+ *
+ * @param length How many hops will the path have.
+ *
+ * @return A newly allocated path with a peer array of the specified length.
+ */
+struct CadetPeerPath *
+path_new (unsigned int length);
+
+
+/**
+ * Invert the path.
+ *
+ * @param path The path to invert.
+ */
+void
+path_invert (struct CadetPeerPath *path);
+
+
+/**
+ * Duplicate a path, incrementing short peer's rc.
+ *
+ * @param path The path to duplicate.
+ */
+struct CadetPeerPath *
+path_duplicate (struct CadetPeerPath *path);
+
+
+/**
+ * Get the length of a path.
+ *
+ * @param path The path to measure, with the local peer at any point of it.
+ *
+ * @return Number of hops to reach destination.
+ * UINT_MAX in case the peer is not in the path.
+ */
+unsigned int
+path_get_length (struct CadetPeerPath *path);
+
+
+/**
+ * Destroy the path and free any allocated resources linked to it
+ *
+ * @param p the path to destroy
+ *
+ * @return GNUNET_OK on success
+ */
+int
+path_destroy (struct CadetPeerPath *p);
+
+
+/******************************************************************************/
+
+/**
+ * Iterator over all children of a node.
+ *
+ * @param cls Closure.
+ * @param peer_id Short ID of the peer.
+ */
+typedef void (*CadetTreeCallback) (void *cls, GNUNET_PEER_Id peer_id);
+
+
+/**
+ * Iterator over all nodes in a tree.
+ *
+ * @param cls Closure.
+ * @param peer_id Short ID of the peer.
+ * @param peer_id Short ID of the parent of the peer.
+ */
+typedef void (*CadetWholeTreeCallback) (void *cls,
+ GNUNET_PEER_Id peer_id,
+ GNUNET_PEER_Id parent_id);
+
+/**
+ * Create a new tunnel tree associated to a tunnel
+ *
+ * @param peer A short peer id of the root of the tree
+ *
+ * @return A newly allocated and initialized tunnel tree
+ */
+struct CadetTunnelTree *
+tree_new (GNUNET_PEER_Id peer);
+
+
+/**
+ * Set the status of a node.
+ *
+ * @param tree Tree.
+ * @param peer A short peer id of the node.
+ * @param status New status to set.
+ */
+void
+tree_set_status (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer,
+ enum CadetPeerState status);
+
+
+/**
+ * Get the status of a node.
+ *
+ * @param tree Tree whose local id we want to now.
+ * @param peer A short peer id of the node.
+ *
+ * @return Short peer id of local peer.
+ */
+enum CadetPeerState
+tree_get_status (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer);
+
+
+/**
+ * Get the id of the predecessor of the local node.
+ *
+ * @param tree Tree whose local id we want to now.
+ *
+ * @return Short peer id of local peer.
+ */
+GNUNET_PEER_Id
+tree_get_predecessor (struct CadetTunnelTree *tree);
+
+
+/**
+ * Find the first peer whom to send a packet to go down this path
+ *
+ * @param t The tunnel tree to use
+ * @param peer The peerinfo of the peer we are trying to reach
+ *
+ * @return peerinfo of the peer who is the first hop in the tunnel
+ * NULL on error
+ */
+struct GNUNET_PeerIdentity *
+tree_get_first_hop (struct CadetTunnelTree *t, GNUNET_PEER_Id peer);
+
+
+/**
+ * Find the given peer in the tree.
+ *
+ * @param tree Tree where to look for the peer.
+ * @param peer_id Peer to find.
+ *
+ * @return Pointer to the node of the peer. NULL if not found.
+ */
+struct CadetTunnelTreeNode *
+tree_find_peer (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer_id);
+
+
+/**
+ * Iterate over all children of the local node.
+ *
+ * @param tree Tree to use. Must have "me" set.
+ * @param cb Callback to call over each child.
+ * @param cb_cls Closure for @c cb.
+ */
+void
+tree_iterate_children (struct CadetTunnelTree *tree,
+ CadetTreeCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Iterate over all nodes in the tree.
+ *
+ * @param tree Tree to use..
+ * @param cb Callback to call over each child.
+ * @param cb_cls Closure for @c cb.
+ *
+ * TODO: recursive implementation? (s/heap/stack/g)
+ */
+void
+tree_iterate_all (struct CadetTunnelTree *tree,
+ CadetWholeTreeCallback cb,
+ void *cb_cls);
+
+/**
+ * Count how many children does the local node have in the tree.
+ *
+ * @param tree Tree to use. Must have "me" set.
+ */
+unsigned int
+tree_count_children (struct CadetTunnelTree *tree);
+
+
+/**
+ * Recusively update the info about what is the first hop to reach the node
+ *
+ * @param tree Tree this nodes belongs to.
+ * @param parent_id Short ID from node form which to start updating.
+ * @param hop If known, ID of the first hop.
+ * If not known, NULL to find out and pass on children.
+ */
+void
+tree_update_first_hops (struct CadetTunnelTree *tree, GNUNET_PEER_Id parent_id,
+ struct GNUNET_PeerIdentity *hop);
+
+/**
+ * Delete the current path to the peer, including all now unused relays.
+ * The destination peer is NOT destroyed, it is returned in order to either set
+ * a new path to it or destroy it explicitly, taking care of it's child nodes.
+ *
+ * @param t Tunnel tree where to delete the path from.
+ * @param peer_id Short ID of the destination peer whose path we want to
remove.
+ * @param cb Callback to use to notify about which peers are going to be
+ * disconnected.
+ * @param cbcls Closure for cb.
+ *
+ * @return pointer to the pathless node.
+ * NULL when not found
+ */
+struct CadetTunnelTreeNode *
+tree_del_path (struct CadetTunnelTree *t, GNUNET_PEER_Id peer_id,
+ CadetTreeCallback cb, void *cbcls);
+
+
+/**
+ * Return a newly allocated individual path to reach a peer from the local
peer,
+ * according to the path tree of some tunnel.
+ *
+ * @param t Tunnel from which to read the path tree
+ * @param peer Destination peer to whom we want a path
+ *
+ * @return A newly allocated individual path to reach the destination peer.
+ * Path must be destroyed afterwards.
+ */
+struct CadetPeerPath *
+tree_get_path_to_peer (struct CadetTunnelTree *t, GNUNET_PEER_Id peer);
+
+
+/**
+ * Integrate a stand alone path into the tunnel tree.
+ *
+ * @param t Tunnel where to add the new path.
+ * @param p Path to be integrated.
+ * @param cb Callback to use to notify about peers temporarily disconnecting.
+ * @param cbcls Closure for cb.
+ *
+ * @return GNUNET_OK in case of success.
+ * GNUNET_SYSERR in case of error.
+ */
+int
+tree_add_path (struct CadetTunnelTree *t, const struct CadetPeerPath *p,
+ CadetTreeCallback cb, void *cbcls);
+
+
+/**
+ * Notifies a tree that a connection it might be using is broken.
+ * Marks all peers down the paths as disconnected and notifies the client.
+ *
+ * @param t Tree to use.
+ * @param p1 Short id of one of the peers (order unimportant)
+ * @param p2 Short id of one of the peers (order unimportant)
+ * @param cb Function to call for every peer that is marked as disconnected.
+ * @param cbcls Closure for cb.
+ *
+ * @return Short ID of the first disconnected peer in the tree.
+ */
+GNUNET_PEER_Id
+tree_notify_connection_broken (struct CadetTunnelTree *t, GNUNET_PEER_Id p1,
+ GNUNET_PEER_Id p2, CadetTreeCallback cb,
+ void *cbcls);
+
+
+/**
+ * Deletes a peer from a tunnel, liberating all unused resources on the path to
+ * it. It shouldn't have children, if it has they will be destroyed as well.
+ * If the tree is not local and no longer has any paths, the root node will be
+ * destroyed and marked as NULL.
+ *
+ * FIXME: dont destroy the root
+ *
+ * @param t Tunnel tree to use.
+ * @param peer Short ID of the peer to remove from the tunnel tree.
+ * @param cb Callback to notify client of disconnected peers.
+ * @param cbcls Closure for cb.
+ *
+ * @return GNUNET_YES if the tunnel still has nodes
+ */
+int
+tree_del_peer (struct CadetTunnelTree *t, GNUNET_PEER_Id peer,
+ CadetTreeCallback cb, void *cbcls);
+
+
+/**
+ * Get the cost of the path relative to the already built tunnel tree
+ *
+ * @param t The tunnel tree to which compare
+ * @param path The individual path to reach a peer
+ *
+ * @return Number of hops to reach destination, UINT_MAX in case the peer is
not
+ * in the path
+ */
+unsigned int
+tree_get_path_cost (struct CadetTunnelTree *t, struct CadetPeerPath *path);
+
+
+/**
+ * Print the tree on stderr
+ *
+ * @param t The tree
+ */
+void
+tree_debug (struct CadetTunnelTree *t);
+
+
+/**
+ * Destroy the whole tree and free all used memory and Peer_Ids
+ *
+ * @param t Tree to be destroyed
+ */
+void
+tree_destroy (struct CadetTunnelTree *t);
Copied: gnunet/src/cadet/gnunet-cadet-profiler.c (from rev 33185,
gnunet/src/mesh/gnunet-cadet-profiler.c)
===================================================================
--- gnunet/src/cadet/gnunet-cadet-profiler.c (rev 0)
+++ gnunet/src/cadet/gnunet-cadet-profiler.c 2014-05-07 12:07:16 UTC (rev
33186)
@@ -0,0 +1,1092 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file cadet/gnunet-cadet-profiler.c
+ *
+ * @brief Profiler for cadet experiments.
+ */
+#include <stdio.h>
+#include "platform.h"
+#include "cadet_test_lib.h"
+#include "gnunet_cadet_service.h"
+#include "gnunet_statistics_service.h"
+
+
+#define PING 1
+#define PONG 2
+
+
+/**
+ * Paximum ping period in milliseconds. Real period = rand (0, PING_PERIOD)
+ */
+#define PING_PERIOD 1000
+
+/**
+ * How long until we give up on connecting the peers?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
+
+/**
+ * Time to wait for stuff that should be rather fast
+ */
+#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
300)
+
+/**
+ * Total number of rounds.
+ */
+#define number_rounds sizeof(rounds)/sizeof(rounds[0])
+
+/**
+ * Ratio of peers active. First round always is 1.0.
+ */
+static float rounds[] = {0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.0};
+
+/**
+ * Message type for pings.
+ */
+struct CadetPingMessage
+{
+ /**
+ * Header. Type PING/PONG.
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Message number.
+ */
+ uint32_t counter;
+
+ /**
+ * Time the message was sent.
+ */
+ struct GNUNET_TIME_AbsoluteNBO timestamp;
+
+ /**
+ * Round number.
+ */
+ uint32_t round_number;
+};
+
+/**
+ * Peer description.
+ */
+struct CadetPeer
+{
+ /**
+ * Testbed Operation (to get peer id, etc).
+ */
+ struct GNUNET_TESTBED_Operation *op;
+
+ /**
+ * Peer ID.
+ */
+ struct GNUNET_PeerIdentity id;
+
+ /**
+ * Cadet handle for the root peer
+ */
+ struct GNUNET_CADET_Handle *cadet;
+
+ /**
+ * Channel handle for the root peer
+ */
+ struct GNUNET_CADET_Channel *ch;
+
+ /**
+ * Channel handle for the dest peer
+ */
+ struct GNUNET_CADET_Channel *incoming_ch;
+
+ /**
+ * Channel handle for a warmup channel.
+ */
+ struct GNUNET_CADET_Channel *warmup_ch;
+
+ /**
+ * Number of payload packes sent
+ */
+ int data_sent;
+
+ /**
+ * Number of payload packets received
+ */
+ int data_received;
+
+ /**
+ * Is peer up?
+ */
+ int up;
+
+ /**
+ * Destinaton to ping.
+ */
+ struct CadetPeer *dest;
+
+ /**
+ * Incoming channel for pings.
+ */
+ struct CadetPeer *incoming;
+
+ /**
+ * Task to do the next ping.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier ping_task;
+
+ float mean[number_rounds];
+ float var[number_rounds];
+ unsigned int pongs[number_rounds];
+ unsigned int pings[number_rounds];
+
+};
+
+/**
+ * Duration of each round.
+ */
+static struct GNUNET_TIME_Relative round_time;
+
+/**
+ * GNUNET_PeerIdentity -> CadetPeer
+ */
+static struct GNUNET_CONTAINER_MultiPeerMap *ids;
+
+/**
+ * Testbed peer handles.
+ */
+static struct GNUNET_TESTBED_Peer **testbed_handles;
+
+/**
+ * Testbed Operation (to get stats).
+ */
+static struct GNUNET_TESTBED_Operation *stats_op;
+
+/**
+ * Operation to get peer ids.
+ */
+struct CadetPeer *peers;
+
+/**
+ * Peer ids counter.
+ */
+static unsigned int p_ids;
+
+/**
+ * Total number of peers.
+ */
+static unsigned long long peers_total;
+
+/**
+ * Number of currently running peers.
+ */
+static unsigned long long peers_running;
+
+/**
+ * Number of peers doing pings.
+ */
+static unsigned long long peers_pinging;
+
+/**
+ * Test context (to shut down).
+ */
+static struct GNUNET_CADET_TEST_Context *test_ctx;
+
+/**
+ * Task called to shutdown test.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle;
+
+/**
+ * Task called to disconnect peers, before shutdown.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
+
+/**
+ * Task to perform tests
+ */
+static GNUNET_SCHEDULER_TaskIdentifier test_task;
+
+/**
+ * Round number.
+ */
+static unsigned int current_round;
+
+/**
+ * Do preconnect? (Each peer creates a tunnel to one other peer).
+ */
+static int do_warmup;
+
+/**
+ * Warmup progress.
+ */
+static unsigned int peers_warmup;
+
+/**
+ * Flag to notify callbacks not to generate any new traffic anymore.
+ */
+static int test_finished;
+
+
+/**
+ * START THE TEST ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES.
+ *
+ * Testcase continues when the root receives confirmation of connected peers,
+ * on callback funtion ch.
+ *
+ * @param cls Closure (unsued).
+ * @param tc Task Context.
+ */
+static void
+start_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Calculate a random delay.
+ *
+ * @param max Exclusive maximum, in ms.
+ *
+ * @return A time between 0 a max-1 ms.
+ */
+static struct GNUNET_TIME_Relative
+delay_ms_rnd (unsigned int max)
+{
+ unsigned int rnd;
+
+ rnd = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, max);
+ return GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, rnd);
+}
+
+
+/**
+ * Get the index of a peer in the peers array.
+ *
+ * @param peer Peer whose index to get.
+ *
+ * @return Index of peer in peers.
+ */
+static unsigned int
+get_index (struct CadetPeer *peer)
+{
+ return peer - peers;
+}
+
+
+/**
+ * Show the results of the test (banwidth acheived) and log them to GAUGER
+ */
+static void
+show_end_data (void)
+{
+ struct CadetPeer *peer;
+ unsigned int i;
+ unsigned int j;
+
+ for (i = 0; i < number_rounds; i++)
+ {
+ for (j = 0; j < peers_pinging; j++)
+ {
+ peer = &peers[j];
+ FPRINTF (stdout,
+ "ROUND %3u PEER %3u: %10.2f / %10.2f, PINGS: %3u, PONGS: %3u\n",
+ i, j, peer->mean[i], sqrt (peer->var[i] / (peer->pongs[i] - 1)),
+ peer->pings[i], peer->pongs[i]);
+ }
+ }
+}
+
+
+/**
+ * Shut down peergroup, clean up.
+ *
+ * @param cls Closure (unused).
+ * @param tc Task Context.
+ */
+static void
+shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Ending test.\n");
+ shutdown_handle = GNUNET_SCHEDULER_NO_TASK;
+}
+
+
+/**
+ * Disconnect from cadet services af all peers, call shutdown.
+ *
+ * @param cls Closure (unused).
+ * @param tc Task Context.
+ */
+static void
+disconnect_cadet_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext
*tc)
+{
+ long line = (long) cls;
+ unsigned int i;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "disconnecting cadet service, called from line %ld\n", line);
+ disconnect_task = GNUNET_SCHEDULER_NO_TASK;
+ for (i = 0; i < peers_total; i++)
+ {
+ if (NULL != peers[i].op)
+ GNUNET_TESTBED_operation_done (peers[i].op);
+
+ if (peers[i].up != GNUNET_YES)
+ continue;
+
+ if (NULL != peers[i].ch)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u: channel %p\n", i, peers[i].ch);
+ GNUNET_CADET_channel_destroy (peers[i].ch);
+ }
+ if (NULL != peers[i].warmup_ch)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u: warmup channel %p\n",
+ i, peers[i].warmup_ch);
+ GNUNET_CADET_channel_destroy (peers[i].warmup_ch);
+ }
+ if (NULL != peers[i].incoming_ch)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u: incoming channel %p\n",
+ i, peers[i].incoming_ch);
+ GNUNET_CADET_channel_destroy (peers[i].incoming_ch);
+ }
+ }
+ GNUNET_CADET_TEST_cleanup (test_ctx);
+ if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle)
+ {
+ GNUNET_SCHEDULER_cancel (shutdown_handle);
+ }
+ shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
+}
+
+
+/**
+ * Finish test normally: schedule disconnect and shutdown
+ *
+ * @param line Line in the code the abort is requested from (__LINE__).
+ */
+static void
+abort_test (long line)
+{
+ if (disconnect_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (disconnect_task);
+ disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
+ (void *) line);
+ }
+}
+
+/**
+ * Stats callback. Finish the stats testbed operation and when all stats have
+ * been iterated, shutdown the test.
+ *
+ * @param cls closure
+ * @param op the operation that has been finished
+ * @param emsg error message in case the operation has failed; will be NULL if
+ * operation has executed successfully.
+ */
+static void
+stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "... collecting statistics done.\n");
+ GNUNET_TESTBED_operation_done (stats_op);
+
+ if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
+ GNUNET_SCHEDULER_cancel (disconnect_task);
+ disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
+ (void *) __LINE__);
+
+}
+
+
+/**
+ * Process statistic values.
+ *
+ * @param cls closure
+ * @param peer the peer the statistic belong to
+ * @param subsystem name of subsystem that created the statistic
+ * @param name the name of the datum
+ * @param value the current value
+ * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
+ * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
+ */
+static int
+stats_iterator (void *cls, const struct GNUNET_TESTBED_Peer *peer,
+ const char *subsystem, const char *name,
+ uint64_t value, int is_persistent)
+{
+ uint32_t i;
+
+ i = GNUNET_TESTBED_get_index (peer);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " STATS %u - %s [%s]: %llu\n",
+ i, subsystem, name, value);
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Task check that keepalives were sent and received.
+ *
+ * @param cls Closure (NULL).
+ * @param tc Task Context.
+ */
+static void
+collect_stats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
+ return;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Start collecting statistics...\n");
+ stats_op = GNUNET_TESTBED_get_statistics (peers_total, testbed_handles,
+ NULL, NULL,
+ stats_iterator, stats_cont, NULL);
+}
+
+
+/**
+ * @brief Finish profiler normally. Signal finish and start collecting stats.
+ *
+ * @param cls Closure (unused).
+ * @param tc Task context.
+ */
+static void
+finish_profiler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
+ return;
+
+ test_finished = GNUNET_YES;
+ show_end_data();
+ GNUNET_SCHEDULER_add_now (&collect_stats, NULL);
+}
+
+/**
+ * Set the total number of running peers.
+ *
+ * @param target Desired number of running peers.
+ */
+static void
+adjust_running_peers (unsigned int target)
+{
+ struct GNUNET_TESTBED_Operation *op;
+ unsigned int delta;
+ unsigned int run;
+ unsigned int i;
+ unsigned int r;
+
+ GNUNET_assert (target <= peers_total);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "adjust peers to %u\n", target);
+ if (target > peers_running)
+ {
+ delta = target - peers_running;
+ run = GNUNET_YES;
+ }
+ else
+ {
+ delta = peers_running - target;
+ run = GNUNET_NO;
+ }
+
+ for (i = 0; i < delta; i++)
+ {
+ do {
+ r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+ peers_total - peers_pinging);
+ r += peers_pinging;
+ } while (peers[r].up == run || NULL != peers[r].incoming);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "St%s peer %u: %s\n",
+ run ? "arting" : "opping", r, GNUNET_i2s (&peers[r].id));
+
+ if (GNUNET_SCHEDULER_NO_TASK != peers[r].ping_task)
+ GNUNET_SCHEDULER_cancel (peers[r].ping_task);
+ peers[r].ping_task = GNUNET_SCHEDULER_NO_TASK;
+
+ peers[r].up = run;
+
+ if (NULL != peers[r].ch)
+ GNUNET_CADET_channel_destroy (peers[r].ch);
+ peers[r].ch = NULL;
+ if (NULL != peers[r].dest)
+ {
+ if (NULL != peers[r].dest->incoming_ch)
+ GNUNET_CADET_channel_destroy (peers[r].dest->incoming_ch);
+ peers[r].dest->incoming_ch = NULL;
+ }
+
+ op = GNUNET_TESTBED_peer_manage_service (&peers[r], testbed_handles[r],
+ "cadet", NULL, NULL, run);
+ GNUNET_break (NULL != op);
+ peers_running += run ? 1 : -1;
+ GNUNET_assert (peers_running > 0);
+ }
+}
+
+
+/**
+ * @brief Move to next round.
+ *
+ * @param cls Closure (round #).
+ * @param tc Task context.
+ */
+static void
+next_rnd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
+ return;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "ROUND %ld\n", current_round);
+ if (0.0 == rounds[current_round])
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Finishing\n");
+ GNUNET_SCHEDULER_add_now (&finish_profiler, NULL);
+ return;
+ }
+ adjust_running_peers (rounds[current_round] * peers_total);
+ current_round++;
+
+ GNUNET_SCHEDULER_add_delayed (round_time, &next_rnd, NULL);
+}
+
+
+/**
+ * Transmit ping callback.
+ *
+ * @param cls Closure (peer for PING, NULL for PONG).
+ * @param size Size of the tranmist buffer.
+ * @param buf Pointer to the beginning of the buffer.
+ *
+ * @return Number of bytes written to buf.
+ */
+static size_t
+tmt_rdy_ping (void *cls, size_t size, void *buf);
+
+
+/**
+ * Transmit pong callback.
+ *
+ * @param cls Closure (copy of PING message, to be freed).
+ * @param size Size of the buffer we have.
+ * @param buf Buffer to copy data to.
+ */
+static size_t
+tmt_rdy_pong (void *cls, size_t size, void *buf)
+{
+ struct CadetPingMessage *ping = cls;
+ struct CadetPingMessage *pong;
+
+ if (0 == size || NULL == buf)
+ {
+ GNUNET_free (ping);
+ return 0;
+ }
+ pong = (struct CadetPingMessage *) buf;
+ memcpy (pong, ping, sizeof (*ping));
+ pong->header.type = htons (PONG);
+
+ GNUNET_free (ping);
+ return sizeof (*ping);
+}
+
+
+/**
+ * @brief Send a ping to destination
+ *
+ * @param cls Closure (peer).
+ * @param tc Task context.
+ */
+static void
+ping (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct CadetPeer *peer = (struct CadetPeer *) cls;
+
+ peer->ping_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0
+ || GNUNET_YES == test_finished)
+ return;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u -> %u (%u)\n",
+ get_index (peer), get_index (peer->dest), peer->data_sent);
+
+ GNUNET_CADET_notify_transmit_ready (peer->ch, GNUNET_NO,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ sizeof (struct CadetPingMessage),
+ &tmt_rdy_ping, peer);
+}
+
+/**
+ * @brief Reply with a pong to origin.
+ *
+ * @param cls Closure (peer).
+ * @param tc Task context.
+ */
+static void
+pong (struct GNUNET_CADET_Channel *channel, const struct CadetPingMessage
*ping)
+{
+ struct CadetPingMessage *copy;
+
+ copy = GNUNET_new (struct CadetPingMessage);
+ memcpy (copy, ping, sizeof (*ping));
+ GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ sizeof (struct CadetPingMessage),
+ &tmt_rdy_pong, copy);
+}
+
+
+/**
+ * Transmit ping callback
+ *
+ * @param cls Closure (peer).
+ * @param size Size of the buffer we have.
+ * @param buf Buffer to copy data to.
+ */
+static size_t
+tmt_rdy_ping (void *cls, size_t size, void *buf)
+{
+ struct CadetPeer *peer = (struct CadetPeer *) cls;
+ struct CadetPingMessage *msg = buf;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tmt_rdy called, filling buffer\n");
+ if (size < sizeof (struct CadetPingMessage) || NULL == buf)
+ {
+ GNUNET_break (GNUNET_YES == test_finished);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "size %u, buf %p, data_sent %u, data_received %u\n",
+ size, buf, peer->data_sent, peer->data_received);
+
+ return 0;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending: msg %d\n", peer->data_sent);
+ msg->header.size = htons (size);
+ msg->header.type = htons (PING);
+ msg->counter = htonl (peer->data_sent++);
+ msg->round_number = htonl (current_round);
+ msg->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
+ peer->pings[current_round]++;
+ peer->ping_task = GNUNET_SCHEDULER_add_delayed (delay_ms_rnd (PING_PERIOD),
+ &ping, peer);
+
+ return sizeof (struct CadetPingMessage);
+}
+
+
+/**
+ * Function is called whenever a PING message is received.
+ *
+ * @param cls closure (peer #, set from GNUNET_CADET_connect)
+ * @param channel connection to the other end
+ * @param channel_ctx place to store local state associated with the channel
+ * @param message the actual message
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+int
+ping_handler (void *cls, struct GNUNET_CADET_Channel *channel,
+ void **channel_ctx,
+ const struct GNUNET_MessageHeader *message)
+{
+ long n = (long) cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%u got PING\n", n);
+ GNUNET_CADET_receive_done (channel);
+ if (GNUNET_NO == test_finished)
+ pong (channel, (struct CadetPingMessage *) message);
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function is called whenever a PONG message is received.
+ *
+ * @param cls closure (peer #, set from GNUNET_CADET_connect)
+ * @param channel connection to the other end
+ * @param channel_ctx place to store local state associated with the channel
+ * @param message the actual message
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+int
+pong_handler (void *cls, struct GNUNET_CADET_Channel *channel,
+ void **channel_ctx,
+ const struct GNUNET_MessageHeader *message)
+{
+ long n = (long) cls;
+ struct CadetPeer *peer;
+ struct CadetPingMessage *msg;
+ struct GNUNET_TIME_Absolute send_time;
+ struct GNUNET_TIME_Relative latency;
+ unsigned int r /* Ping round */;
+ float delta;
+
+ GNUNET_CADET_receive_done (channel);
+ peer = &peers[n];
+
+ msg = (struct CadetPingMessage *) message;
+
+ send_time = GNUNET_TIME_absolute_ntoh (msg->timestamp);
+ latency = GNUNET_TIME_absolute_get_duration (send_time);
+ r = ntohl (msg->round_number);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u <- %u (%u) latency: %s\n",
+ get_index (peer), get_index (peer->dest), ntohl (msg->counter),
+ GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO));
+
+ /* Online variance calculation */
+ peer->pongs[r]++;
+ delta = latency.rel_value_us - peer->mean[r];
+ peer->mean[r] = peer->mean[r] + delta/peer->pongs[r];
+ peer->var[r] += delta * (latency.rel_value_us - peer->mean[r]);
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Handlers, for diverse services
+ */
+static struct GNUNET_CADET_MessageHandler handlers[] = {
+ {&ping_handler, PING, sizeof (struct CadetPingMessage)},
+ {&pong_handler, PONG, sizeof (struct CadetPingMessage)},
+ {NULL, 0, 0}
+};
+
+
+/**
+ * Method called whenever another peer has added us to a channel
+ * the other peer initiated.
+ *
+ * @param cls Closure.
+ * @param channel New handle to the channel.
+ * @param initiator Peer that started the channel.
+ * @param port Port this channel is connected to.
+ * @param options channel option flags
+ * @return Initial channel context for the channel
+ * (can be NULL -- that's not an error).
+ */
+static void *
+incoming_channel (void *cls, struct GNUNET_CADET_Channel *channel,
+ const struct GNUNET_PeerIdentity *initiator,
+ uint32_t port, enum GNUNET_CADET_ChannelOption options)
+{
+ long n = (long) cls;
+ struct CadetPeer *peer;
+
+ peer = GNUNET_CONTAINER_multipeermap_get (ids, initiator);
+ GNUNET_assert (NULL != peer);
+ if (NULL == peers[n].incoming)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "WARMUP %3u: %u <= %u\n",
+ peers_warmup, n, get_index (peer));
+ peers_warmup++;
+ if (peers_warmup < peers_total)
+ return NULL;
+ if (GNUNET_SCHEDULER_NO_TASK != test_task)
+ {
+ GNUNET_SCHEDULER_cancel (test_task);
+ test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+ &start_test, NULL);
+ }
+ return NULL;
+ }
+ GNUNET_assert (peer == peers[n].incoming);
+ GNUNET_assert (peer->dest == &peers[n]);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u <= %u %p\n",
+ n, get_index (peer), channel);
+ peers[n].incoming_ch = channel;
+
+ return NULL;
+}
+
+/**
+ * Function called whenever an inbound channel is destroyed. Should clean up
+ * any associated state.
+ *
+ * @param cls closure (set from GNUNET_CADET_connect)
+ * @param channel connection to the other end (henceforth invalid)
+ * @param channel_ctx place where local state associated
+ * with the channel is stored
+ */
+static void
+channel_cleaner (void *cls, const struct GNUNET_CADET_Channel *channel,
+ void *channel_ctx)
+{
+ long n = (long) cls;
+ struct CadetPeer *peer = &peers[n];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Channel %p disconnected at peer %ld\n", channel, n);
+ if (peer->ch == channel)
+ peer->ch = NULL;
+}
+
+
+/**
+ * Select a random peer that has no incoming channel
+ *
+ * @param peer ID of the peer connecting. NULL if irrelevant (warmup).
+ *
+ * @return Random peer not yet connected to.
+ */
+static struct CadetPeer *
+select_random_peer (struct CadetPeer *peer)
+{
+ unsigned int r;
+
+ do
+ {
+ r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, peers_total);
+ } while (NULL != peers[r].incoming);
+ peers[r].incoming = peer;
+
+ return &peers[r];
+}
+
+/**
+ * START THE TEST ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES.
+ *
+ * Testcase continues when the root receives confirmation of connected peers,
+ * on callback funtion ch.
+ *
+ * @param cls Closure (unsued).
+ * @param tc Task Context.
+ */
+static void
+start_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ enum GNUNET_CADET_ChannelOption flags;
+ unsigned long i;
+
+ test_task = GNUNET_SCHEDULER_NO_TASK;
+ if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
+ return;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Start profiler\n");
+
+ flags = GNUNET_CADET_OPTION_DEFAULT;
+ for (i = 0; i < peers_pinging; i++)
+ {
+ peers[i].dest = select_random_peer (&peers[i]);
+ peers[i].ch = GNUNET_CADET_channel_create (peers[i].cadet, NULL,
+ &peers[i].dest->id,
+ 1, flags);
+ if (NULL == peers[i].ch)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Channel %lu failed\n", i);
+ GNUNET_CADET_TEST_cleanup (test_ctx);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u => %u %p\n",
+ i, get_index (peers[i].dest), peers[i].ch);
+ peers[i].ping_task = GNUNET_SCHEDULER_add_delayed (delay_ms_rnd (2000),
+ &ping, &peers[i]);
+ }
+ peers_running = peers_total;
+ if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
+ GNUNET_SCHEDULER_cancel (disconnect_task);
+ disconnect_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(round_time,
+ number_rounds
+ 1),
+ &disconnect_cadet_peers,
+ (void *) __LINE__);
+ GNUNET_SCHEDULER_add_delayed (round_time, &next_rnd, NULL);
+}
+
+
+/**
+ * Do warmup: create some channels to spread information about the topology.
+ */
+static void
+warmup (void)
+{
+ struct CadetPeer *peer;
+ unsigned int i;
+
+ for (i = 0; i < peers_total; i++)
+ {
+ peer = select_random_peer (NULL);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "WARMUP %u => %u\n",
+ i, get_index (peer));
+ peers[i].warmup_ch =
+ GNUNET_CADET_channel_create (peers[i].cadet, NULL, &peer->id,
+ 1, GNUNET_CADET_OPTION_DEFAULT);
+ if (NULL == peers[i].warmup_ch)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Warmup %u failed\n", i);
+ GNUNET_CADET_TEST_cleanup (test_ctx);
+ return;
+ }
+ }
+}
+
+/**
+ * Callback to be called when the requested peer information is available
+ *
+ * @param cls the closure from GNUNET_TESTBED_peer_get_information()
+ * @param op the operation this callback corresponds to
+ * @param pinfo the result; will be NULL if the operation has failed
+ * @param emsg error message if the operation has failed;
+ * NULL if the operation is successfull
+ */
+static void
+peer_id_cb (void *cls,
+ struct GNUNET_TESTBED_Operation *op,
+ const struct GNUNET_TESTBED_PeerInformation *pinfo,
+ const char *emsg)
+{
+ long n = (long) cls;
+
+ if (NULL == pinfo || NULL != emsg)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg);
+ abort_test (__LINE__);
+ return;
+ }
+ peers[n].id = *(pinfo->result.id);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, " %u id: %s\n",
+ n, GNUNET_i2s (&peers[n].id));
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CONTAINER_multipeermap_put (ids, &peers[n].id,
&peers[n],
+
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
+
+ GNUNET_TESTBED_operation_done (peers[n].op);
+ peers[n].op = NULL;
+
+ p_ids++;
+ if (p_ids < peers_total)
+ return;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got all IDs, starting profiler\n");
+ if (do_warmup)
+ {
+ struct GNUNET_TIME_Relative delay;
+
+ warmup();
+ delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
+ 100 * peers_total);
+ test_task = GNUNET_SCHEDULER_add_delayed (delay, &start_test, NULL);
+ return; /* start_test from incoming_channel */
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Starting in a second...\n");
+ test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+ &start_test, NULL);
+}
+
+/**
+ * test main: start test when all peers are connected
+ *
+ * @param cls Closure.
+ * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
+ * @param num_peers Number of peers that are running.
+ * @param testbed_peers Array of peers.
+ * @param cadetes Handle to each of the CADETs of the peers.
+ */
+static void
+tmain (void *cls,
+ struct GNUNET_CADET_TEST_Context *ctx,
+ unsigned int num_peers,
+ struct GNUNET_TESTBED_Peer **testbed_peers,
+ struct GNUNET_CADET_Handle **cadetes)
+{
+ unsigned long i;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n");
+ test_ctx = ctx;
+ GNUNET_assert (peers_total == num_peers);
+ peers_running = num_peers;
+ testbed_handles = testbed_peers;
+ disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
+ &disconnect_cadet_peers,
+ (void *) __LINE__);
+ shutdown_handle = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ &shutdown_task, NULL);
+ for (i = 0; i < peers_total; i++)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requesting id %ld\n", i);
+ peers[i].up = GNUNET_YES;
+ peers[i].cadet = cadetes[i];
+ peers[i].op =
+ GNUNET_TESTBED_peer_get_information (testbed_handles[i],
+ GNUNET_TESTBED_PIT_IDENTITY,
+ &peer_id_cb, (void *) i);
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "requested peer ids\n");
+ /* Continues from pi_cb -> do_test */
+}
+
+
+/**
+ * Main: start profiler.
+ */
+int
+main (int argc, char *argv[])
+{
+ static uint32_t ports[2];
+ const char *config_file;
+
+ config_file = ".profiler.conf";
+
+ if (4 > argc)
+ {
+ fprintf (stderr, "usage: %s ROUND_TIME PEERS PINGS [DO_WARMUP]\n",
argv[0]);
+ fprintf (stderr, "example: %s 30s 16 1 Y\n", argv[0]);
+ return 1;
+ }
+
+ if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_relative (argv[1],
&round_time))
+ {
+ fprintf (stderr, "%s is not a valid time\n", argv[1]);
+ return 1;
+ }
+
+ peers_total = atoll (argv[2]);
+ if (2 > peers_total)
+ {
+ fprintf (stderr, "%s peers is not valid (> 2)\n", argv[1]);
+ return 1;
+ }
+ peers = GNUNET_malloc (sizeof (struct CadetPeer) * peers_total);
+
+ peers_pinging = atoll (argv[3]);
+
+ if (peers_total < 2 * peers_pinging)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "not enough peers, total should be > 2 * peers_pinging\n");
+ return 1;
+ }
+
+ do_warmup = (5 > argc || argv[4][0] != 'N');
+
+ ids = GNUNET_CONTAINER_multipeermap_create (2 * peers_total, GNUNET_YES);
+ GNUNET_assert (NULL != ids);
+ p_ids = 0;
+ test_finished = GNUNET_NO;
+ ports[0] = 1;
+ ports[1] = 0;
+ GNUNET_CADET_TEST_run ("cadet-profiler", config_file, peers_total,
+ &tmain, NULL, /* tmain cls */
+ &incoming_channel, &channel_cleaner,
+ handlers, ports);
+ GNUNET_free (peers);
+
+ return 0;
+}
+
+/* end of gnunet-cadet-profiler.c */
+
Copied: gnunet/src/cadet/gnunet-cadet.c (from rev 33185,
gnunet/src/mesh/gnunet-cadet.c)
===================================================================
--- gnunet/src/cadet/gnunet-cadet.c (rev 0)
+++ gnunet/src/cadet/gnunet-cadet.c 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,851 @@
+/*
+ This file is part of GNUnet.
+ (C) 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file cadet/gnunet-cadet.c
+ * @brief Print information about cadet tunnels and peers.
+ * @author Bartlomiej Polot
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_cadet_service.h"
+#include "cadet.h"
+
+
+/**
+ * Option -m.
+ */
+static int monitor_connections;
+
+/**
+ * Option -P.
+ */
+static int request_peers;
+
+/**
+ * Option --peer
+ */
+static char *peer_id;
+
+/**
+ * Option -T.
+ */
+static int request_tunnels;
+
+/**
+ * Option --tunnel
+ */
+static char *tunnel_id;
+
+/**
+ * Option --connection
+ */
+static char *conn_id;
+
+/**
+ * Option --channel
+ */
+static char *channel_id;
+
+/**
+ * Port to listen on (-p).
+ */
+static uint32_t listen_port;
+
+/**
+ * Request echo service
+ */
+int echo;
+
+/**
+ * Time of last echo request.
+ */
+struct GNUNET_TIME_Absolute echo_time;
+
+/**
+ * Task for next echo request.
+ */
+GNUNET_SCHEDULER_TaskIdentifier echo_task;
+
+/**
+ * Peer to connect to.
+ */
+static char *target_id;
+
+/**
+ * Port to connect to
+ */
+static uint32_t target_port;
+
+/**
+ * Data pending in netcat mode.
+ */
+size_t data_size;
+
+
+/**
+ * Cadet handle.
+ */
+static struct GNUNET_CADET_Handle *mh;
+
+/**
+ * Channel handle.
+ */
+static struct GNUNET_CADET_Channel *ch;
+
+/**
+ * Shutdown task handle.
+ */
+GNUNET_SCHEDULER_TaskIdentifier sd;
+
+
+
+static void
+listen_stdio (void);
+
+
+
+/**
+ * Task run in monitor mode when the user presses CTRL-C to abort.
+ * Stops monitoring activity.
+ *
+ * @param cls Closure (unused).
+ * @param tc scheduler context
+ */
+static void
+shutdown_task (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
+ if (NULL != ch)
+ {
+ GNUNET_CADET_channel_destroy (ch);
+ ch = NULL;
+ }
+ if (NULL != mh)
+ {
+ GNUNET_CADET_disconnect (mh);
+ mh = NULL;
+ }
+}
+
+
+/**
+ * Function called to notify a client about the connection
+ * begin ready to queue more data. "buf" will be
+ * NULL and "size" zero if the connection was closed for
+ * writing in the meantime.
+ *
+ * FIXME
+ *
+ * @param cls closure
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+size_t
+data_ready (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_MessageHeader *msg;
+ size_t total_size;
+
+ if (NULL == buf || 0 == size)
+ {
+ GNUNET_SCHEDULER_shutdown();
+ return 0;
+ }
+
+ total_size = data_size + sizeof (struct GNUNET_MessageHeader);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending %u bytes\n", data_size);
+ GNUNET_assert (size >= total_size);
+
+ msg = buf;
+ msg->size = htons (total_size);
+ msg->type = htons (GNUNET_MESSAGE_TYPE_CADET_CLI);
+ memcpy (&msg[1], cls, data_size);
+ if (GNUNET_NO == echo)
+ {
+ listen_stdio ();
+ }
+ else
+ {
+ echo_time = GNUNET_TIME_absolute_get ();
+ }
+
+ return total_size;
+}
+
+
+/**
+ * Task run in monitor mode when the user presses CTRL-C to abort.
+ * Stops monitoring activity.
+ *
+ * @param cls Closure (unused).
+ * @param tc scheduler context
+ */
+static void
+read_stdio (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ static char buf[60000];
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ {
+ return;
+ }
+
+ data_size = read (0, buf, 60000);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "stdio read %u bytes\n", data_size);
+ if (data_size < 1)
+ {
+ GNUNET_SCHEDULER_shutdown();
+ return;
+ }
+ GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ data_size
+ + sizeof (struct GNUNET_MessageHeader),
+ &data_ready, buf);
+}
+
+
+/**
+ * Start listening to stdin
+ */
+static void
+listen_stdio (void)
+{
+ struct GNUNET_NETWORK_FDSet *rs;
+
+ rs = GNUNET_NETWORK_fdset_create ();
+ GNUNET_NETWORK_fdset_set_native (rs, 0);
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ rs, NULL,
+ &read_stdio, NULL);
+ GNUNET_NETWORK_fdset_destroy (rs);
+}
+
+
+/**
+ * Function called whenever a channel is destroyed. Should clean up
+ * any associated state.
+ *
+ * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
+ *
+ * @param cls closure (set from #GNUNET_CADET_connect)
+ * @param channel connection to the other end (henceforth invalid)
+ * @param channel_ctx place where local state associated
+ * with the channel is stored
+ */
+static void
+channel_ended (void *cls,
+ const struct GNUNET_CADET_Channel *channel,
+ void *channel_ctx)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel ended!\n");
+ GNUNET_break (channel == ch);
+ ch = NULL;
+ GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
+ * Method called whenever another peer has added us to a channel
+ * the other peer initiated.
+ * Only called (once) upon reception of data with a message type which was
+ * subscribed to in #GNUNET_CADET_connect.
+ *
+ * A call to #GNUNET_CADET_channel_destroy causes te channel to be ignored. In
+ * this case the handler MUST return NULL.
+ *
+ * @param cls closure
+ * @param channel new handle to the channel
+ * @param initiator peer that started the channel
+ * @param port Port this channel is for.
+ * @param options CadetOption flag field, with all active option bits set to 1.
+ *
+ * @return initial channel context for the channel
+ * (can be NULL -- that's not an error)
+ */
+static void *
+channel_incoming (void *cls,
+ struct GNUNET_CADET_Channel * channel,
+ const struct GNUNET_PeerIdentity * initiator,
+ uint32_t port, enum GNUNET_CADET_ChannelOption options)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Incoming channel %p on port %u\n",
+ channel, port);
+ if (NULL != ch)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "A channel already exists\n");
+ return NULL;
+ }
+ if (0 == listen_port)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not listening to channels\n");
+ return NULL;
+ }
+ ch = channel;
+ if (GNUNET_NO == echo)
+ {
+ listen_stdio ();
+ return NULL;
+ }
+ data_size = 0;
+ return NULL;
+}
+
+/**
+ * @brief Send an echo request to the remote peer.
+ *
+ * @param cls Closure (NULL).
+ * @param tc Task context.
+ */
+static void
+send_echo (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) || NULL == ch)
+ return;
+
+ GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ sizeof (struct GNUNET_MessageHeader),
+ &data_ready, NULL);
+}
+
+
+
+/**
+ * Call CADET's monitor API, get info of one connection.
+ *
+ * @param cls Closure (unused).
+ * @param tc TaskContext
+ */
+static void
+create_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_PeerIdentity pid;
+ enum GNUNET_CADET_ChannelOption opt;
+
+ GNUNET_assert (NULL == ch);
+
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
+ strlen (target_id),
+ &pid.public_key))
+ {
+ FPRINTF (stderr,
+ _("Invalid target `%s'\n"),
+ target_id);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to `%s'\n", target_id);
+ opt = GNUNET_CADET_OPTION_DEFAULT | GNUNET_CADET_OPTION_RELIABLE;
+ ch = GNUNET_CADET_channel_create (mh, NULL, &pid, target_port, opt);
+ if (GNUNET_NO == echo)
+ listen_stdio ();
+ else
+ GNUNET_SCHEDULER_add_now (send_echo, NULL);
+}
+
+
+/**
+ * Function called whenever a message is received.
+ *
+ * Each time the function must call #GNUNET_CADET_receive_done on the channel
+ * in order to receive the next message. This doesn't need to be immediate:
+ * can be delayed if some processing is done on the message.
+ *
+ * @param cls Closure (set from #GNUNET_CADET_connect).
+ * @param channel Connection to the other end.
+ * @param channel_ctx Place to store local state associated with the channel.
+ * @param message The actual message.
+ * @return #GNUNET_OK to keep the channel open,
+ * #GNUNET_SYSERR to close it (signal serious error).
+ */
+static int
+data_callback (void *cls,
+ struct GNUNET_CADET_Channel *channel,
+ void **channel_ctx,
+ const struct GNUNET_MessageHeader *message)
+{
+ uint16_t len;
+ ssize_t done;
+ uint16_t off;
+ const char *buf;
+ GNUNET_break (ch == channel);
+
+ if (GNUNET_YES == echo)
+ {
+ if (0 != listen_port)
+ {
+ /* Just listening to echo incoming messages*/
+ GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ sizeof (struct GNUNET_MessageHeader),
+ &data_ready, NULL);
+ return GNUNET_OK;
+ }
+ else
+ {
+ struct GNUNET_TIME_Relative latency;
+
+ latency = GNUNET_TIME_absolute_get_duration (echo_time);
+ echo_time = GNUNET_TIME_UNIT_FOREVER_ABS;
+ FPRINTF (stdout, "time: %s\n",
+ GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO));
+ echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+ &send_echo, NULL);
+ }
+ }
+
+ len = ntohs (message->size) - sizeof (*message);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u bytes\n", len);
+ buf = (const char *) &message[1];
+ off = 0;
+ while (off < len)
+ {
+ done = write (1, &buf[off], len - off);
+ if (done <= 0)
+ {
+ if (-1 == done)
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+ "write");
+ return GNUNET_SYSERR;
+ }
+ off += done;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Method called to retrieve information about all peers in CADET, called
+ * once per peer.
+ *
+ * After last peer has been reported, an additional call with NULL is done.
+ *
+ * @param cls Closure.
+ * @param peer Peer, or NULL on "EOF".
+ * @param tunnel Do we have a tunnel towards this peer?
+ * @param n_paths Number of known paths towards this peer.
+ * @param best_path How long is the best path?
+ * (0 = unknown, 1 = ourselves, 2 = neighbor)
+ */
+static void
+peers_callback (void *cls, const struct GNUNET_PeerIdentity *peer,
+ int tunnel, unsigned int n_paths, unsigned int best_path)
+{
+ if (NULL == peer)
+ {
+ if (GNUNET_YES != monitor_connections)
+ {
+ GNUNET_SCHEDULER_shutdown();
+ }
+ return;
+ }
+ FPRINTF (stdout, "%s tunnel: %c, paths: %u\n",
+ GNUNET_i2s_full (peer), tunnel ? 'Y' : 'N', n_paths);
+}
+
+/**
+ * Method called to retrieve information about a specific peer
+ * known to the service.
+ *
+ * @param cls Closure.
+ * @param peer Peer ID.
+ * @param tunnel Do we have a tunnel towards this peer? #GNUNET_YES/#GNUNET_NO
+ * @param neighbor Is this a direct neighbor? #GNUNET_YES/#GNUNET_NO
+ * @param n_paths Number of paths known towards peer.
+ * @param paths Array of PEER_IDs representing all paths to reach the peer.
+ * Each path starts with the local peer.
+ * Each path ends with the destination peer (given in @c peer).
+ */
+void
+peer_callback (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ int tunnel,
+ int neighbor,
+ unsigned int n_paths,
+ struct GNUNET_PeerIdentity *paths)
+{
+}
+
+
+/**
+ * Method called to retrieve information about all tunnels in CADET.
+ *
+ * @param cls Closure.
+ * @param peer Destination peer.
+ * @param channels Number of channels.
+ * @param connections Number of connections.
+ * @param estate Encryption state.
+ * @param cstate Connectivity state.
+ */
+void
+tunnels_callback (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ unsigned int channels,
+ unsigned int connections,
+ uint16_t estate,
+ uint16_t cstate)
+{
+ if (NULL == peer)
+ {
+ if (GNUNET_YES != monitor_connections)
+ {
+ GNUNET_SCHEDULER_shutdown();
+ }
+ return;
+ }
+ FPRINTF (stdout, "%s [ENC: %u, CON: %u] CHs: %u, CONNs: %u\n",
+ GNUNET_i2s_full (peer), estate, cstate, channels, connections);
+}
+
+
+/**
+ * Method called to retrieve information about a specific tunnel the cadet peer
+ * has established, o`r is trying to establish.
+ *
+ * @param cls Closure.
+ * @param peer Peer towards whom the tunnel is directed.
+ * @param n_channels Number of channels.
+ * @param n_connections Number of connections.
+ * @param channels Channels.
+ * @param connections Connections.
+ * @param estate Encryption status.
+ * @param cstate Connectivity status.
+ */
+void
+tunnel_callback (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ unsigned int n_channels,
+ unsigned int n_connections,
+ uint32_t *channels,
+ struct GNUNET_CADET_Hash *connections,
+ unsigned int estate,
+ unsigned int cstate)
+{
+ unsigned int i;
+
+ if (NULL != peer)
+ {
+ FPRINTF (stdout, "Tunnel %s\n", GNUNET_i2s_full (peer));
+ FPRINTF (stdout, "- %u channels\n", n_channels);
+ for (i = 0; i < n_channels; i++)
+ FPRINTF (stdout, " %u\n", channels[i]);
+ FPRINTF (stdout, "- %u connections\n", n_connections);
+ for (i = 0; i < n_connections; i++)
+ FPRINTF (stdout, " %s\n", GM_h2s (&connections[i]));
+ FPRINTF (stdout, "- enc state: %u\n", estate);
+ FPRINTF (stdout, "- con state: %u\n", cstate);
+ }
+ if (GNUNET_YES != monitor_connections)
+ {
+ GNUNET_SCHEDULER_shutdown();
+ }
+ return;
+
+}
+
+
+/**
+ * Call CADET's meta API, get all peers known to a peer.
+ *
+ * @param cls Closure (unused).
+ * @param tc TaskContext
+ */
+static void
+get_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
+ return;
+ }
+ GNUNET_CADET_get_peers (mh, &peers_callback, NULL);
+}
+
+
+/**
+ * Call CADET's monitor API, get info of one peer.
+ *
+ * @param cls Closure (unused).
+ * @param tc TaskContext
+ */
+static void
+show_peer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_PeerIdentity pid;
+
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id,
+ strlen (peer_id),
+ &pid.public_key))
+ {
+ fprintf (stderr,
+ _("Invalid peer ID `%s'\n"),
+ peer_id);
+ GNUNET_SCHEDULER_shutdown();
+ return;
+ }
+ GNUNET_CADET_get_peer (mh, &pid, peer_callback, NULL);
+}
+
+/**
+ * Call CADET's meta API, get all tunnels known to a peer.
+ *
+ * @param cls Closure (unused).
+ * @param tc TaskContext
+ */
+static void
+get_tunnels (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
+ return;
+ }
+ GNUNET_CADET_get_tunnels (mh, &tunnels_callback, NULL);
+}
+
+
+/**
+ * Call CADET's monitor API, get info of one tunnel.
+ *
+ * @param cls Closure (unused).
+ * @param tc TaskContext
+ */
+static void
+show_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_PeerIdentity pid;
+
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_public_key_from_string (tunnel_id,
+ strlen (tunnel_id),
+ &pid.public_key))
+ {
+ fprintf (stderr,
+ _("Invalid tunnel owner `%s'\n"),
+ tunnel_id);
+ GNUNET_SCHEDULER_shutdown();
+ return;
+ }
+ GNUNET_CADET_get_tunnel (mh, &pid, tunnel_callback, NULL);
+}
+
+
+/**
+ * Call CADET's monitor API, get info of one channel.
+ *
+ * @param cls Closure (unused).
+ * @param tc TaskContext
+ */
+static void
+show_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+
+}
+
+
+/**
+ * Call CADET's monitor API, get info of one connection.
+ *
+ * @param cls Closure (unused).
+ * @param tc TaskContext
+ */
+static void
+show_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+
+}
+
+
+/**
+ * Main function that will be run by the scheduler.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be
NULL!)
+ * @param cfg configuration
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ GNUNET_CADET_InboundChannelNotificationHandler *newch = NULL;
+ GNUNET_CADET_ChannelEndHandler *endch = NULL;
+ static const struct GNUNET_CADET_MessageHandler handlers[] = {
+ {&data_callback, GNUNET_MESSAGE_TYPE_CADET_CLI, 0},
+ {NULL, 0, 0} /* FIXME add option to monitor msg types */
+ };
+ static uint32_t *ports = NULL;
+ /* FIXME add option to monitor apps */
+
+ target_id = args[0];
+ target_port = args[0] && args[1] ? atoi(args[1]) : 0;
+ if ( (0 != (request_peers | request_tunnels)
+ || 0 != monitor_connections
+ || NULL != tunnel_id
+ || NULL != conn_id
+ || NULL != channel_id)
+ && target_id != NULL)
+ {
+ FPRINTF (stderr,
+ _("You must NOT give a TARGET"
+ "when using 'request all' options\n"));
+ return;
+ }
+
+ if (NULL != target_id)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating channel to %s\n",
+ target_id);
+ GNUNET_SCHEDULER_add_now (&create_channel, NULL);
+ endch = &channel_ended;
+ }
+ else if (0 != listen_port)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Listen\n");
+ newch = &channel_incoming;
+ endch = &channel_ended;
+ ports = GNUNET_malloc (sizeof (uint32_t) * 2);
+ ports[0] = listen_port;
+ }
+ else if (NULL != peer_id)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show peer\n");
+ GNUNET_SCHEDULER_add_now (&show_peer, NULL);
+ }
+ else if (NULL != tunnel_id)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show tunnel\n");
+ GNUNET_SCHEDULER_add_now (&show_tunnel, NULL);
+ }
+ else if (NULL != channel_id)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show channel\n");
+ GNUNET_SCHEDULER_add_now (&show_channel, NULL);
+ }
+ else if (NULL != conn_id)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show connection\n");
+ GNUNET_SCHEDULER_add_now (&show_connection, NULL);
+ }
+ else if (GNUNET_YES == request_peers)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all peers\n");
+ GNUNET_SCHEDULER_add_now (&get_peers, NULL);
+ }
+ else if (GNUNET_YES == request_tunnels)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all tunnels\n");
+ GNUNET_SCHEDULER_add_now (&get_tunnels, NULL);
+ }
+ else
+ {
+ FPRINTF (stderr, "No action requested\n");
+ return;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to cadet\n");
+ mh = GNUNET_CADET_connect (cfg,
+ NULL, /* cls */
+ newch, /* new channel */
+ endch, /* cleaner */
+ handlers,
+ ports);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done\n");
+ if (NULL == mh)
+ GNUNET_SCHEDULER_add_now (shutdown_task, NULL);
+ else
+ sd = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ shutdown_task, NULL);
+
+}
+
+
+/**
+ * The main function to obtain peer information.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+ int res;
+ const char helpstr[] = "Create channels and retreive info about cadets
status.";
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+// {'a', "channel", "TUNNEL_ID:CHANNEL_ID",
+// gettext_noop ("provide information about a particular channel"),
+// GNUNET_YES, &GNUNET_GETOPT_set_string, &channel_id},
+ {'C', "connection", "CONNECTION_ID",
+ gettext_noop ("provide information about a particular connection"),
+ GNUNET_YES, &GNUNET_GETOPT_set_string, &conn_id},
+ {'e', "echo", NULL,
+ gettext_noop ("activate echo mode"),
+ GNUNET_NO, &GNUNET_GETOPT_set_one, &echo},
+// {'m', "monitor", NULL,
+// gettext_noop ("provide information about all events (continuously)"),
+// GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor_mode},
+ {'o', "open-port", NULL,
+ gettext_noop ("port to listen to (default; 0)"),
+ GNUNET_YES, &GNUNET_GETOPT_set_uint, &listen_port},
+ {'p', "peer", "PEER_ID",
+ gettext_noop ("provide information about a patricular peer"),
+ GNUNET_YES, &GNUNET_GETOPT_set_string, &peer_id},
+ {'P', "peers", NULL,
+ gettext_noop ("provide information about all peers"),
+ GNUNET_NO, &GNUNET_GETOPT_set_one, &request_peers},
+ {'t', "tunnel", "TUNNEL_ID",
+ gettext_noop ("provide information about a particular tunnel"),
+ GNUNET_YES, &GNUNET_GETOPT_set_string, &tunnel_id},
+ {'T', "tunnels", NULL,
+ gettext_noop ("provide information about all tunnels"),
+ GNUNET_NO, &GNUNET_GETOPT_set_one, &request_tunnels},
+
+ GNUNET_GETOPT_OPTION_END
+ };
+
+ monitor_connections = GNUNET_NO;
+
+ if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
+ return 2;
+
+ res = GNUNET_PROGRAM_run (argc, argv, "gnunet-cadet (OPTIONS | TARGET PORT)",
+ gettext_noop (helpstr),
+ options, &run, NULL);
+
+ GNUNET_free ((void *) argv);
+
+ if (GNUNET_OK == res)
+ return 0;
+ else
+ return 1;
+}
+
+/* end of gnunet-cadet.c */
Copied: gnunet/src/cadet/gnunet-service-cadet.c (from rev 33185,
gnunet/src/mesh/gnunet-service-cadet.c)
===================================================================
--- gnunet/src/cadet/gnunet-service-cadet.c (rev 0)
+++ gnunet/src/cadet/gnunet-service-cadet.c 2014-05-07 12:07:16 UTC (rev
33186)
@@ -0,0 +1,181 @@
+/*
+ This file is part of GNUnet.
+ (C) 2001-2013 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet.c
+ * @brief GNUnet CADET service with encryption
+ * @author Bartlomiej Polot
+ *
+ * FIXME in progress:
+ * - rekey - reliability interaction
+ * - channel retransmit timing
+ *
+ * TODO:
+ * - relay corking down to core
+ * - set ttl relative to path length
+ * TODO END
+ *
+ * Dictionary:
+ * - peer: other cadet instance. If there is direct connection it's a neighbor.
+ * - tunnel: encrypted connection to a peer, neighbor or not.
+ * - channel: connection between two clients, on the same or different peers.
+ * have properties like reliability.
+ * - path: series of directly connected peer from one peer to another.
+ * - connection: path which is being used in a tunnel.
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "cadet.h"
+#include "gnunet_statistics_service.h"
+
+#include "gnunet-service-cadet_local.h"
+#include "gnunet-service-cadet_channel.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_tunnel.h"
+#include "gnunet-service-cadet_dht.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_hello.h"
+
+
+/******************************************************************************/
+/*********************** GLOBAL VARIABLES
****************************/
+/******************************************************************************/
+
+/****************************** Global variables
******************************/
+
+/**
+ * Handle to the statistics service.
+ */
+struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Local peer own ID (memory efficient handle).
+ */
+GNUNET_PEER_Id myid;
+
+/**
+ * Local peer own ID (full value).
+ */
+struct GNUNET_PeerIdentity my_full_id;
+
+
+/**
+ * Signal that shutdown is happening: prevent recover measures.
+ */
+int shutting_down;
+
+/*************************** Static global variables
**************************/
+
+/**
+ * Own private key.
+ */
+static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
+
+
+/******************************************************************************/
+/************************ MAIN FUNCTIONS
****************************/
+/******************************************************************************/
+
+/**
+ * Task run during shutdown.
+ *
+ * @param cls unused
+ * @param tc unused
+ */
+static void
+shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutting down\n");
+
+ shutting_down = GNUNET_YES;
+
+ GML_shutdown ();
+ GMH_shutdown ();
+ GMC_shutdown ();
+ GMT_shutdown ();
+ GMD_shutdown ();
+ GMP_shutdown ();
+
+ GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
+ stats = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shut down\n");
+}
+
+
+/**
+ * Process cadet requests.
+ *
+ * @param cls closure
+ * @param server the initialized server
+ * @param c configuration to use
+ */
+static void
+run (void *cls, struct GNUNET_SERVER_Handle *server,
+ const struct GNUNET_CONFIGURATION_Handle *c)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting to run\n");
+
+ stats = GNUNET_STATISTICS_create ("cadet", c);
+
+ /* Scheduled the task to clean up when shutdown is called */
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
+ NULL);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "reading key\n");
+ my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
+ GNUNET_assert (NULL != my_private_key);
+ GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_full_id.public_key);
+ myid = GNUNET_PEER_intern (&my_full_id);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "STARTING SERVICE (CADET) for peer [%s]\n",
+ GNUNET_i2s (&my_full_id));
+
+ GML_init (server); /* Local clients */
+ GMH_init (c); /* Hellos */
+ GMC_init (c); /* Connections */
+ GMP_init (c); /* Peers */
+ GMD_init (c); /* DHT */
+ GMT_init (c, my_private_key); /* Tunnels */
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cadet service running\n");
+}
+
+
+/**
+ * The main function for the cadet service.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+ int ret;
+ int r;
+
+ shutting_down = GNUNET_NO;
+ r = GNUNET_SERVICE_run (argc, argv, "cadet", GNUNET_SERVICE_OPTION_NONE,
&run,
+ NULL);
+ GNUNET_free (my_private_key);
+ ret = (GNUNET_OK == r) ? 0 : 1;
+
+ return ret;
+}
Copied: gnunet/src/cadet/gnunet-service-cadet_channel.c (from rev 33185,
gnunet/src/mesh/gnunet-service-cadet_channel.c)
===================================================================
--- gnunet/src/cadet/gnunet-service-cadet_channel.c
(rev 0)
+++ gnunet/src/cadet/gnunet-service-cadet_channel.c 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -0,0 +1,2432 @@
+/*
+ This file is part of GNUnet.
+ (C) 2013 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+#include "gnunet_statistics_service.h"
+
+#include "cadet.h"
+#include "cadet_protocol.h"
+
+#include "gnunet-service-cadet_channel.h"
+#include "gnunet-service-cadet_local.h"
+#include "gnunet-service-cadet_tunnel.h"
+#include "gnunet-service-cadet_peer.h"
+
+#define LOG(level, ...) GNUNET_log_from(level,"cadet-chn",__VA_ARGS__)
+
+#define CADET_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(\
+ GNUNET_TIME_UNIT_MILLISECONDS, 250)
+#define CADET_RETRANSMIT_MARGIN 4
+
+
+/**
+ * All the states a connection can be in.
+ */
+enum CadetChannelState
+{
+ /**
+ * Uninitialized status, should never appear in operation.
+ */
+ CADET_CHANNEL_NEW,
+
+ /**
+ * Connection create message sent, waiting for ACK.
+ */
+ CADET_CHANNEL_SENT,
+
+ /**
+ * Connection confirmed, ready to carry traffic.
+ */
+ CADET_CHANNEL_READY,
+};
+
+
+/**
+ * Info holder for channel messages in queues.
+ */
+struct CadetChannelQueue
+{
+ /**
+ * Tunnel Queue.
+ */
+ struct CadetTunnel3Queue *tq;
+
+ /**
+ * Message type (DATA/DATA_ACK)
+ */
+ uint16_t type;
+
+ /**
+ * Message copy (for DATAs, to start retransmission timer)
+ */
+ struct CadetReliableMessage *copy;
+
+ /**
+ * Reliability (for DATA_ACKs, to access rel->ack_q)
+ */
+ struct CadetChannelReliability *rel;
+};
+
+
+/**
+ * Info needed to retry a message in case it gets lost.
+ */
+struct CadetReliableMessage
+{
+ /**
+ * Double linked list, FIFO style
+ */
+ struct CadetReliableMessage *next;
+ struct CadetReliableMessage *prev;
+
+ /**
+ * Type of message (payload, channel management).
+ */
+ int16_t type;
+
+ /**
+ * Tunnel Reliability queue this message is in.
+ */
+ struct CadetChannelReliability *rel;
+
+ /**
+ * ID of the message (ACK needed to free)
+ */
+ uint32_t mid;
+
+ /**
+ * Tunnel Queue.
+ */
+ struct CadetChannelQueue *chq;
+
+ /**
+ * When was this message issued (to calculate ACK delay)
+ */
+ struct GNUNET_TIME_Absolute timestamp;
+
+ /* struct GNUNET_CADET_Data with payload */
+};
+
+
+/**
+ * Info about the traffic state for a client in a channel.
+ */
+struct CadetChannelReliability
+{
+ /**
+ * Channel this is about.
+ */
+ struct CadetChannel *ch;
+
+ /**
+ * DLL of messages sent and not yet ACK'd.
+ */
+ struct CadetReliableMessage *head_sent;
+ struct CadetReliableMessage *tail_sent;
+
+ /**
+ * DLL of messages received out of order.
+ */
+ struct CadetReliableMessage *head_recv;
+ struct CadetReliableMessage *tail_recv;
+
+ /**
+ * Messages received.
+ */
+ unsigned int n_recv;
+
+ /**
+ * Next MID to use for outgoing traffic.
+ */
+ uint32_t mid_send;
+
+ /**
+ * Next MID expected for incoming traffic.
+ */
+ uint32_t mid_recv;
+
+ /**
+ * Handle for queued unique data CREATE, DATA_ACK.
+ */
+ struct CadetChannelQueue *uniq;
+
+ /**
+ * Can we send data to the client?
+ */
+ int client_ready;
+
+ /**
+ * Can the client send data to us?
+ */
+ int client_allowed;
+
+ /**
+ * Task to resend/poll in case no ACK is received.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier retry_task;
+
+ /**
+ * Counter for exponential backoff.
+ */
+ struct GNUNET_TIME_Relative retry_timer;
+
+ /**
+ * How long does it usually take to get an ACK.
+ */
+ struct GNUNET_TIME_Relative expected_delay;
+};
+
+
+/**
+ * Struct containing all information regarding a channel to a remote client.
+ */
+struct CadetChannel
+{
+ /**
+ * Tunnel this channel is in.
+ */
+ struct CadetTunnel3 *t;
+
+ /**
+ * Destination port of the channel.
+ */
+ uint32_t port;
+
+ /**
+ * Global channel number ( < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+ */
+ CADET_ChannelNumber gid;
+
+ /**
+ * Local tunnel number for root (owner) client.
+ * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI or 0 )
+ */
+ CADET_ChannelNumber lid_root;
+
+ /**
+ * Local tunnel number for local destination clients (incoming number)
+ * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV or 0).
+ */
+ CADET_ChannelNumber lid_dest;
+
+ /**
+ * Channel state.
+ */
+ enum CadetChannelState state;
+
+ /**
+ * Is the tunnel bufferless (minimum latency)?
+ */
+ int nobuffer;
+
+ /**
+ * Is the tunnel reliable?
+ */
+ int reliable;
+
+ /**
+ * Last time the channel was used
+ */
+ struct GNUNET_TIME_Absolute timestamp;
+
+ /**
+ * Client owner of the tunnel, if any
+ */
+ struct CadetClient *root;
+
+ /**
+ * Client destination of the tunnel, if any.
+ */
+ struct CadetClient *dest;
+
+ /**
+ * Flag to signal the destruction of the channel.
+ * If this is set GNUNET_YES the channel will be destroyed
+ * when the queue is empty.
+ */
+ int destroy;
+
+ /**
+ * Total (reliable) messages pending ACK for this channel.
+ */
+ unsigned int pending_messages;
+
+ /**
+ * Reliability data.
+ * Only present (non-NULL) at the owner of a tunnel.
+ */
+ struct CadetChannelReliability *root_rel;
+
+ /**
+ * Reliability data.
+ * Only present (non-NULL) at the destination of a tunnel.
+ */
+ struct CadetChannelReliability *dest_rel;
+
+};
+
+
+/******************************************************************************/
+/******************************* GLOBALS
***********************************/
+/******************************************************************************/
+
+/**
+ * Global handle to the statistics service.
+ */
+extern struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Local peer own ID (memory efficient handle).
+ */
+extern GNUNET_PEER_Id myid;
+
+
+/******************************************************************************/
+/******************************** STATIC
***********************************/
+/******************************************************************************/
+
+/**
+ * Destroy a reliable message after it has been acknowledged, either by
+ * direct mid ACK or bitfield. Updates the appropriate data structures and
+ * timers and frees all memory.
+ *
+ * @param copy Message that is no longer needed: remote peer got it.
+ * @param update_time Is the timing information relevant?
+ * If this message is ACK in a batch the timing information
+ * is skewed by the retransmission, count only for the
+ * retransmitted message.
+ */
+static int
+rel_message_free (struct CadetReliableMessage *copy, int update_time);
+
+/**
+ * send a channel create message.
+ *
+ * @param ch Channel for which to send.
+ */
+static void
+send_create (struct CadetChannel *ch);
+
+/**
+ * Confirm we got a channel create, FWD ack.
+ *
+ * @param ch The channel to confirm.
+ * @param fwd Should we send a FWD ACK? (going dest->root)
+ * @param reaction This ACK is a reaction to a duplicate CREATE, don't save.
+ */
+static void
+send_ack (struct CadetChannel *ch, int fwd, int reaction);
+
+
+
+/**
+ * Test if the channel is loopback: both root and dest are on the local peer.
+ *
+ * @param ch Channel to test.
+ *
+ * @return #GNUNET_YES if channel is loopback, #GNUNET_NO otherwise.
+ */
+static int
+is_loopback (const struct CadetChannel *ch)
+{
+ if (NULL != ch->t)
+ return GMT_is_loopback (ch->t);
+
+ return (NULL != ch->root && NULL != ch->dest);
+}
+
+
+/**
+ * Save a copy of the data message for later retransmission.
+ *
+ * @param msg Message to copy.
+ * @param mid Message ID.
+ * @param rel Reliability data for retransmission.
+ */
+static struct CadetReliableMessage *
+copy_message (const struct GNUNET_CADET_Data *msg, uint32_t mid,
+ struct CadetChannelReliability *rel)
+{
+ struct CadetReliableMessage *copy;
+ uint16_t size;
+
+ size = ntohs (msg->header.size);
+ copy = GNUNET_malloc (sizeof (*copy) + size);
+ copy->mid = mid;
+ copy->rel = rel;
+ copy->type = GNUNET_MESSAGE_TYPE_CADET_DATA;
+ memcpy (©[1], msg, size);
+
+ return copy;
+}
+
+/**
+ * We have received a message out of order, or the client is not ready.
+ * Buffer it until we receive an ACK from the client or the missing
+ * message from the channel.
+ *
+ * @param msg Message to buffer (MUST be of type CADET_DATA).
+ * @param rel Reliability data to the corresponding direction.
+ */
+static void
+add_buffered_data (const struct GNUNET_CADET_Data *msg,
+ struct CadetChannelReliability *rel)
+{
+ struct CadetReliableMessage *copy;
+ struct CadetReliableMessage *prev;
+ uint32_t mid;
+
+ mid = ntohl (msg->mid);
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data %u\n", mid);
+
+ rel->n_recv++;
+
+ // FIXME do something better than O(n), although n < 64...
+ // FIXME start from the end (most messages are the latest ones)
+ for (prev = rel->head_recv; NULL != prev; prev = prev->next)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " prev %u\n", prev->mid);
+ if (prev->mid == mid)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " already there!\n");
+ return;
+ }
+ else if (GM_is_pid_bigger (prev->mid, mid))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " bingo!\n");
+ copy = copy_message (msg, mid, rel);
+ GNUNET_CONTAINER_DLL_insert_before (rel->head_recv, rel->tail_recv,
+ prev, copy);
+ return;
+ }
+ }
+ copy = copy_message (msg, mid, rel);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " insert at tail!\n");
+ GNUNET_CONTAINER_DLL_insert_tail (rel->head_recv, rel->tail_recv, copy);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data END\n");
+}
+
+
+/**
+ * Add a destination client to a channel, initializing all data structures
+ * in the channel and the client.
+ *
+ * @param ch Channel to which add the destination.
+ * @param c Client which to add to the channel.
+ */
+static void
+add_destination (struct CadetChannel *ch, struct CadetClient *c)
+{
+ if (NULL != ch->dest)
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ /* Assign local id as destination */
+ ch->lid_dest = GML_get_next_chid (c);
+
+ /* Store in client's hashmap */
+ GML_channel_add (c, ch->lid_dest, ch);
+
+ GNUNET_break (NULL == ch->dest_rel);
+ ch->dest_rel = GNUNET_new (struct CadetChannelReliability);
+ ch->dest_rel->ch = ch;
+ ch->dest_rel->expected_delay.rel_value_us = 0;
+ ch->dest_rel->retry_timer = CADET_RETRANSMIT_TIME;
+
+ ch->dest = c;
+}
+
+
+/**
+ * Set options in a channel, extracted from a bit flag field.
+ *
+ * @param ch Channel to set options to.
+ * @param options Bit array in host byte order.
+ */
+static void
+channel_set_options (struct CadetChannel *ch, uint32_t options)
+{
+ ch->nobuffer = (options & GNUNET_CADET_OPTION_NOBUFFER) != 0 ?
+ GNUNET_YES : GNUNET_NO;
+ ch->reliable = (options & GNUNET_CADET_OPTION_RELIABLE) != 0 ?
+ GNUNET_YES : GNUNET_NO;
+}
+
+
+/**
+ * Get a bit flag field with the options of a channel.
+ *
+ * @param ch Channel to get options from.
+ *
+ * @return Bit array in host byte order.
+ */
+static uint32_t
+channel_get_options (struct CadetChannel *ch)
+{
+ uint32_t options;
+
+ options = 0;
+ if (ch->nobuffer)
+ options |= GNUNET_CADET_OPTION_NOBUFFER;
+ if (ch->reliable)
+ options |= GNUNET_CADET_OPTION_RELIABLE;
+
+ return options;
+}
+
+
+/**
+ * Notify a client that the channel is no longer valid.
+ *
+ * @param ch Channel that is destroyed.
+ * @param local_only Should we avoid sending it to other peers?
+ */
+static void
+send_destroy (struct CadetChannel *ch, int local_only)
+{
+ struct GNUNET_CADET_ChannelManage msg;
+
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
+ msg.header.size = htons (sizeof (msg));
+ msg.chid = htonl (ch->gid);
+
+ /* If root is not NULL, notify.
+ * If it's NULL, check lid_root. When a local destroy comes in, root
+ * is set to NULL but lid_root is left untouched. In this case, do nothing,
+ * the client is the one who requested the channel to be destroyed.
+ */
+ if (NULL != ch->root)
+ GML_send_channel_destroy (ch->root, ch->lid_root);
+ else if (0 == ch->lid_root && GNUNET_NO == local_only)
+ GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO, NULL);
+
+ if (NULL != ch->dest)
+ GML_send_channel_destroy (ch->dest, ch->lid_dest);
+ else if (0 == ch->lid_dest && GNUNET_NO == local_only)
+ GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_YES, NULL);
+}
+
+
+/**
+ * Notify the destination client that a new incoming channel was created.
+ *
+ * @param ch Channel that was created.
+ */
+static void
+send_client_create (struct CadetChannel *ch)
+{
+ uint32_t opt;
+
+ if (NULL == ch->dest)
+ return;
+
+ opt = 0;
+ opt |= GNUNET_YES == ch->reliable ? GNUNET_CADET_OPTION_RELIABLE : 0;
+ opt |= GNUNET_YES == ch->nobuffer ? GNUNET_CADET_OPTION_NOBUFFER : 0;
+ GML_send_channel_create (ch->dest, ch->lid_dest, ch->port, opt,
+ GMT_get_destination (ch->t));
+
+}
+
+
+/**
+ * Send data to a client.
+ *
+ * If the client is ready, send directly, otherwise buffer while listening
+ * for a local ACK.
+ *
+ * @param ch Channel
+ * @param msg Message.
+ * @param fwd Is this a fwd (root->dest) message?
+ */
+static void
+send_client_data (struct CadetChannel *ch,
+ const struct GNUNET_CADET_Data *msg,
+ int fwd)
+{
+ if (fwd)
+ {
+ if (ch->dest_rel->client_ready)
+ GML_send_data (ch->dest, msg, ch->lid_dest);
+ else
+ add_buffered_data (msg, ch->dest_rel);
+ }
+ else
+ {
+ if (ch->root_rel->client_ready)
+ GML_send_data (ch->root, msg, ch->lid_root);
+ else
+ add_buffered_data (msg, ch->root_rel);
+ }
+}
+
+
+/**
+ * Send a buffered message to the client, for in order delivery or
+ * as result of client ACK.
+ *
+ * @param ch Channel on which to empty the message buffer.
+ * @param c Client to send to.
+ * @param fwd Is this to send FWD data?.
+ */
+static void
+send_client_buffered_data (struct CadetChannel *ch,
+ struct CadetClient *c,
+ int fwd)
+{
+ struct CadetReliableMessage *copy;
+ struct CadetChannelReliability *rel;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data\n");
+ rel = fwd ? ch->dest_rel : ch->root_rel;
+ if (GNUNET_NO == rel->client_ready)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "client not ready\n");
+ return;
+ }
+
+ copy = rel->head_recv;
+ /* We never buffer channel management messages */
+ if (NULL != copy)
+ {
+ if (copy->mid == rel->mid_recv || GNUNET_NO == ch->reliable)
+ {
+ struct GNUNET_CADET_Data *msg = (struct GNUNET_CADET_Data *) ©[1];
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " have %u! now expecting %u\n",
+ copy->mid, rel->mid_recv + 1);
+ send_client_data (ch, msg, fwd);
+ rel->n_recv--;
+ rel->mid_recv++;
+ GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE RECV %p\n", copy);
+ GNUNET_free (copy);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " reliable && don't have %u, next is %u\n",
+ rel->mid_recv,
+ copy->mid);
+ if (GNUNET_YES == ch->destroy)
+ {
+ /* We don't have the next data piece and the remote peer has closed the
+ * channel. We won't receive it anymore, so just destroy the channel.
+ * FIXME: wait some time to allow other connections to
+ * deliver missing messages
+ */
+ send_destroy (ch, GNUNET_YES);
+ GMCH_destroy (ch);
+ }
+ }
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data END\n");
+}
+
+
+/**
+ * Allow a client to send more data.
+ *
+ * In case the client was already allowed to send data, do nothing.
+ *
+ * @param ch Channel.
+ * @param fwd Is this a FWD ACK? (FWD ACKs are sent to root)
+ */
+static void
+send_client_ack (struct CadetChannel *ch, int fwd)
+{
+ struct CadetChannelReliability *rel = fwd ? ch->root_rel : ch->dest_rel;
+ struct CadetClient *c = fwd ? ch->root : ch->dest;
+
+ if (NULL == c)
+ {
+ GNUNET_break (GNUNET_NO != ch->destroy);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " sending %s ack to client on channel %s\n",
+ GM_f2s (fwd), GMCH_2s (ch));
+
+ if (NULL == rel)
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ if (GNUNET_YES == rel->client_allowed)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " already allowed\n");
+ return;
+ }
+ rel->client_allowed = GNUNET_YES;
+
+ GML_send_ack (c, fwd ? ch->lid_root : ch->lid_dest);
+}
+
+
+/**
+ * Notify the root that the destination rejected the channel.
+ *
+ * @param ch Rejected channel.
+ */
+static void
+send_client_nack (struct CadetChannel *ch)
+{
+ if (NULL == ch->root)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ GML_send_channel_nack (ch->root, ch->lid_root);
+}
+
+
+/**
+ * We haven't received an ACK after a certain time: restransmit the message.
+ *
+ * @param cls Closure (CadetChannelReliability with the message to restransmit)
+ * @param tc TaskContext.
+ */
+static void
+channel_retransmit_message (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct CadetChannelReliability *rel = cls;
+ struct CadetReliableMessage *copy;
+ struct CadetChannel *ch;
+ struct GNUNET_CADET_Data *payload;
+ int fwd;
+
+ rel->retry_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ ch = rel->ch;
+ copy = rel->head_sent;
+ if (NULL == copy)
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ payload = (struct GNUNET_CADET_Data *) ©[1];
+ fwd = (rel == ch->root_rel);
+
+ /* Message not found in the queue that we are going to use. */
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! RETRANSMIT %u\n", copy->mid);
+
+ GMCH_send_prebuilt_message (&payload->header, ch, fwd, copy);
+ GNUNET_STATISTICS_update (stats, "# data retransmitted", 1, GNUNET_NO);
+}
+
+
+/**
+ * We haven't received an Channel ACK after a certain time: resend the CREATE.
+ *
+ * @param cls Closure (CadetChannelReliability of the channel to recreate)
+ * @param tc TaskContext.
+ */
+static void
+channel_recreate (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct CadetChannelReliability *rel = cls;
+
+ rel->retry_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! RE-CREATE\n");
+ GNUNET_STATISTICS_update (stats, "# data retransmitted", 1, GNUNET_NO);
+
+ if (rel == rel->ch->root_rel)
+ {
+ send_create (rel->ch);
+ }
+ else if (rel == rel->ch->dest_rel)
+ {
+ send_ack (rel->ch, GNUNET_YES, GNUNET_NO);
+ }
+ else
+ {
+ GNUNET_break (0);
+ }
+
+}
+
+
+/**
+ * Message has been sent: start retransmission timer.
+ *
+ * @param cls Closure (queue structure).
+ * @param t Tunnel.
+ * @param q Queue handler (no longer valid).
+ * @param type Type of message.
+ * @param size Size of the message.
+ */
+static void
+ch_message_sent (void *cls,
+ struct CadetTunnel3 *t,
+ struct CadetTunnel3Queue *q,
+ uint16_t type, size_t size)
+{
+ struct CadetChannelQueue *chq = cls;
+ struct CadetReliableMessage *copy = chq->copy;
+ struct CadetChannelReliability *rel;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "channel message sent callback %s\n",
+ GM_m2s (chq->type));
+
+ switch (chq->type)
+ {
+ case GNUNET_MESSAGE_TYPE_CADET_DATA:
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SENT DATA MID %u\n", copy->mid);
+ GNUNET_assert (chq == copy->chq);
+ copy->timestamp = GNUNET_TIME_absolute_get ();
+ rel = copy->rel;
+ if (GNUNET_SCHEDULER_NO_TASK == rel->retry_task)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!! scheduling retry in 4 * %s\n",
+ GNUNET_STRINGS_relative_time_to_string (rel->expected_delay,
+ GNUNET_YES));
+ if (0 != rel->expected_delay.rel_value_us)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!! delay != 0\n");
+ rel->retry_timer =
+ GNUNET_TIME_relative_multiply (rel->expected_delay,
+ CADET_RETRANSMIT_MARGIN);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!! delay reset\n");
+ rel->retry_timer = CADET_RETRANSMIT_TIME;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!! using delay %s\n",
+ GNUNET_STRINGS_relative_time_to_string (rel->retry_timer,
+ GNUNET_NO));
+ rel->retry_task =
+ GNUNET_SCHEDULER_add_delayed (rel->retry_timer,
+ &channel_retransmit_message, rel);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!! retry task %u\n", rel->retry_task);
+ }
+ copy->chq = NULL;
+ break;
+
+
+ case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK:
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE:
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK:
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SENT %s\n", GM_m2s (chq->type));
+ rel = chq->rel;
+ GNUNET_assert (rel->uniq == chq);
+ rel->uniq = NULL;
+
+ if (CADET_CHANNEL_READY != rel->ch->state
+ && GNUNET_MESSAGE_TYPE_CADET_DATA_ACK != type
+ && GNUNET_NO == rel->ch->destroy)
+ {
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == rel->retry_task);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! STD BACKOFF %s\n",
+ GNUNET_STRINGS_relative_time_to_string (rel->retry_timer,
+ GNUNET_NO));
+ rel->retry_timer = GNUNET_TIME_STD_BACKOFF (rel->retry_timer);
+ rel->retry_task = GNUNET_SCHEDULER_add_delayed (rel->retry_timer,
+ &channel_recreate,
rel);
+ }
+ break;
+
+ default:
+ GNUNET_break (0);
+ }
+
+ GNUNET_free (chq);
+}
+
+
+/**
+ * send a channel create message.
+ *
+ * @param ch Channel for which to send.
+ */
+static void
+send_create (struct CadetChannel *ch)
+{
+ struct GNUNET_CADET_ChannelCreate msgcc;
+
+ msgcc.header.size = htons (sizeof (msgcc));
+ msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE);
+ msgcc.chid = htonl (ch->gid);
+ msgcc.port = htonl (ch->port);
+ msgcc.opt = htonl (channel_get_options (ch));
+
+ GMCH_send_prebuilt_message (&msgcc.header, ch, GNUNET_YES, NULL);
+}
+
+
+/**
+ * Confirm we got a channel create or FWD ack.
+ *
+ * @param ch The channel to confirm.
+ * @param fwd Should we send a FWD ACK? (going dest->root)
+ * @param reaction This ACK is a reaction to a duplicate CREATE, don't save.
+ */
+static void
+send_ack (struct CadetChannel *ch, int fwd, int reaction)
+{
+ struct GNUNET_CADET_ChannelManage msg;
+
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " sending channel %s ack for channel %s\n",
+ GM_f2s (fwd), GMCH_2s (ch));
+
+ msg.chid = htonl (ch->gid);
+ GMCH_send_prebuilt_message (&msg.header, ch, !fwd, reaction ? &msg : NULL);
+}
+
+
+/**
+ * Send a message and don't keep any info about it: we won't need to cancel it
+ * or resend it.
+ *
+ * @param msg Header of the message to fire away.
+ * @param ch Channel on which the message should go.
+ * @param force Is this a forced (undroppable) message?
+ */
+static void
+fire_and_forget (const struct GNUNET_MessageHeader *msg,
+ struct CadetChannel *ch,
+ int force)
+{
+ GNUNET_break (NULL == GMT_send_prebuilt_message (msg, ch->t, NULL,
+ force, NULL, NULL));
+}
+
+
+/**
+ * Notify that a channel create didn't succeed.
+ *
+ * @param ch The channel to reject.
+ */
+static void
+send_nack (struct CadetChannel *ch)
+{
+ struct GNUNET_CADET_ChannelManage msg;
+
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " sending channel NACK for channel %s\n",
+ GMCH_2s (ch));
+
+ msg.chid = htonl (ch->gid);
+ GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO, NULL);
+}
+
+
+/**
+ * Destroy all reliable messages queued for a channel,
+ * during a channel destruction.
+ * Frees the reliability structure itself.
+ *
+ * @param rel Reliability data for a channel.
+ */
+static void
+channel_rel_free_all (struct CadetChannelReliability *rel)
+{
+ struct CadetReliableMessage *copy;
+ struct CadetReliableMessage *next;
+
+ if (NULL == rel)
+ return;
+
+ for (copy = rel->head_recv; NULL != copy; copy = next)
+ {
+ next = copy->next;
+ GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE BATCH RECV %p\n", copy);
+ GNUNET_break (NULL == copy->chq);
+ GNUNET_free (copy);
+ }
+ for (copy = rel->head_sent; NULL != copy; copy = next)
+ {
+ next = copy->next;
+ GNUNET_CONTAINER_DLL_remove (rel->head_sent, rel->tail_sent, copy);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE BATCH %p\n", copy);
+ if (NULL != copy->chq)
+ {
+ if (NULL != copy->chq->tq)
+ {
+ GMT_cancel (copy->chq->tq);
+ /* ch_message_sent will free copy->q */
+ }
+ else
+ {
+ GNUNET_free (copy->chq);
+ GNUNET_break (0);
+ }
+ }
+ GNUNET_free (copy);
+ }
+ if (NULL != rel->uniq && NULL != rel->uniq->tq)
+ {
+ GMT_cancel (rel->uniq->tq);
+ /* ch_message_sent is called freeing uniq */
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != rel->retry_task)
+ {
+ GNUNET_SCHEDULER_cancel (rel->retry_task);
+ rel->retry_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_free (rel);
+}
+
+
+/**
+ * Mark future messages as ACK'd.
+ *
+ * @param rel Reliability data.
+ * @param msg DataACK message with a bitfield of future ACK'd messages.
+ */
+static void
+channel_rel_free_sent (struct CadetChannelReliability *rel,
+ const struct GNUNET_CADET_DataACK *msg)
+{
+ struct CadetReliableMessage *copy;
+ struct CadetReliableMessage *next;
+ uint64_t bitfield;
+ uint64_t mask;
+ uint32_t mid;
+ uint32_t target;
+ unsigned int i;
+
+ bitfield = msg->futures;
+ mid = ntohl (msg->mid);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "!!! free_sent_reliable %u %llX\n",
+ mid, bitfield);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " rel %p, head %p\n",
+ rel, rel->head_sent);
+ for (i = 0, copy = rel->head_sent;
+ i < 64 && NULL != copy && 0 != bitfield;
+ i++)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " trying bit %u (mid %u)\n",
+ i, mid + i + 1);
+ mask = 0x1LL << i;
+ if (0 == (bitfield & mask))
+ continue;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " set!\n");
+ /* Bit was set, clear the bit from the bitfield */
+ bitfield &= ~mask;
+
+ /* The i-th bit was set. Do we have that copy? */
+ /* Skip copies with mid < target */
+ target = mid + i + 1;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " target %u\n", target);
+ while (NULL != copy && GM_is_pid_bigger (target, copy->mid))
+ copy = copy->next;
+
+ /* Did we run out of copies? (previously freed, it's ok) */
+ if (NULL == copy)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "run out of copies...\n");
+ return;
+ }
+
+ /* Did we overshoot the target? (previously freed, it's ok) */
+ if (GM_is_pid_bigger (copy->mid, target))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " next copy %u\n", copy->mid);
+ continue;
+ }
+
+ /* Now copy->mid == target, free it */
+ next = copy->next;
+ GNUNET_break (GNUNET_YES != rel_message_free (copy, GNUNET_YES));
+ copy = next;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "free_sent_reliable END\n");
+}
+
+
+/**
+ * Destroy a reliable message after it has been acknowledged, either by
+ * direct mid ACK or bitfield. Updates the appropriate data structures and
+ * timers and frees all memory.
+ *
+ * @param copy Message that is no longer needed: remote peer got it.
+ * @param update_time Is the timing information relevant?
+ * If this message is ACK in a batch the timing information
+ * is skewed by the retransmission, count only for the
+ * retransmitted message.
+ *
+ * @return #GNUNET_YES if channel was destroyed as a result of the call,
+ * #GNUNET_NO otherwise.
+ */
+static int
+rel_message_free (struct CadetReliableMessage *copy, int update_time)
+{
+ struct CadetChannelReliability *rel;
+ struct GNUNET_TIME_Relative time;
+
+ rel = copy->rel;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Freeing %u\n", copy->mid);
+ if (update_time)
+ {
+ time = GNUNET_TIME_absolute_get_duration (copy->timestamp);
+ if (0 == rel->expected_delay.rel_value_us)
+ rel->expected_delay = time;
+ else
+ {
+ rel->expected_delay.rel_value_us *= 7;
+ rel->expected_delay.rel_value_us += time.rel_value_us;
+ rel->expected_delay.rel_value_us /= 8;
+ }
+ LOG (GNUNET_ERROR_TYPE_INFO, "!!! took %s, new delay %s\n",
+ GNUNET_STRINGS_relative_time_to_string (time, GNUNET_NO),
+ GNUNET_STRINGS_relative_time_to_string (rel->expected_delay,
+ GNUNET_NO));
+ rel->retry_timer = rel->expected_delay;
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_INFO, "!!! batch free, ignoring timing\n");
+ }
+ rel->ch->pending_messages--;
+ if (NULL != copy->chq)
+ {
+ GMT_cancel (copy->chq->tq);
+ /* copy->q is set to NULL by ch_message_sent */
+ }
+ GNUNET_CONTAINER_DLL_remove (rel->head_sent, rel->tail_sent, copy);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE %p\n", copy);
+ GNUNET_free (copy);
+
+ if (GNUNET_NO != rel->ch->destroy && 0 == rel->ch->pending_messages)
+ {
+ GMCH_destroy (rel->ch);
+ return GNUNET_YES;
+ }
+ return GNUNET_NO;
+}
+
+
+/**
+ * Channel was ACK'd by remote peer, mark as ready and cancel retransmission.
+ *
+ * @param ch Channel to mark as ready.
+ * @param fwd Was the ACK message a FWD ACK? (dest->root, SYNACK)
+ */
+static void
+channel_confirm (struct CadetChannel *ch, int fwd)
+{
+ struct CadetChannelReliability *rel;
+ enum CadetChannelState oldstate;
+
+ rel = fwd ? ch->root_rel : ch->dest_rel;
+ if (NULL == rel)
+ {
+ GNUNET_break (GNUNET_NO != ch->destroy);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " channel confirm %s %s\n",
+ GM_f2s (fwd), GMCH_2s (ch));
+ oldstate = ch->state;
+ ch->state = CADET_CHANNEL_READY;
+
+ if (CADET_CHANNEL_READY != oldstate || GNUNET_YES == is_loopback (ch))
+ {
+ rel->client_ready = GNUNET_YES;
+ rel->expected_delay = rel->retry_timer;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " !! retry timer confirm %s\n",
+ GNUNET_STRINGS_relative_time_to_string (rel->retry_timer, GNUNET_NO));
+ if (GMT_get_connections_buffer (ch->t) > 0 || GMT_is_loopback (ch->t))
+ send_client_ack (ch, fwd);
+
+ if (GNUNET_SCHEDULER_NO_TASK != rel->retry_task)
+ {
+ GNUNET_SCHEDULER_cancel (rel->retry_task);
+ rel->retry_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ else if (NULL != rel->uniq)
+ {
+ GMT_cancel (rel->uniq->tq);
+ /* ch_message_sent will free and NULL uniq */
+ }
+ else
+ {
+ if (GNUNET_NO == is_loopback (ch))
+ {
+ /* We SHOULD have been trying to retransmit this! */
+ GNUNET_break (0);
+ }
+ }
+ }
+
+ /* In case of a FWD ACK (SYNACK) send a BCK ACK (ACK). */
+ if (GNUNET_YES == fwd)
+ send_ack (ch, GNUNET_NO, GNUNET_NO);
+}
+
+
+/**
+ * Save a copy to retransmit in case it gets lost.
+ *
+ * Initializes all needed callbacks and timers.
+ *
+ * @param ch Channel this message goes on.
+ * @param msg Message to copy.
+ * @param fwd Is this fwd traffic?
+ */
+static struct CadetReliableMessage *
+channel_save_copy (struct CadetChannel *ch,
+ const struct GNUNET_MessageHeader *msg,
+ int fwd)
+{
+ struct CadetChannelReliability *rel;
+ struct CadetReliableMessage *copy;
+ uint32_t mid;
+ uint16_t type;
+ uint16_t size;
+
+ rel = fwd ? ch->root_rel : ch->dest_rel;
+ mid = rel->mid_send - 1;
+ type = ntohs (msg->type);
+ size = ntohs (msg->size);
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SAVE %u %s\n", mid, GM_m2s (type));
+ copy = GNUNET_malloc (sizeof (struct CadetReliableMessage) + size);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " at %p\n", copy);
+ copy->mid = mid;
+ copy->rel = rel;
+ copy->type = type;
+ memcpy (©[1], msg, size);
+ GNUNET_CONTAINER_DLL_insert_tail (rel->head_sent, rel->tail_sent, copy);
+ ch->pending_messages++;
+
+ return copy;
+}
+
+
+/**
+ * Create a new channel.
+ *
+ * @param t Tunnel this channel is in.
+ * @param owner Client that owns the channel, NULL for foreign channels.
+ * @param lid_root Local ID for root client.
+ *
+ * @return A new initialized channel. NULL on error.
+ */
+static struct CadetChannel *
+channel_new (struct CadetTunnel3 *t,
+ struct CadetClient *owner,
+ CADET_ChannelNumber lid_root)
+{
+ struct CadetChannel *ch;
+
+ ch = GNUNET_new (struct CadetChannel);
+ ch->root = owner;
+ ch->lid_root = lid_root;
+ ch->t = t;
+
+ GNUNET_STATISTICS_update (stats, "# channels", 1, GNUNET_NO);
+
+ if (NULL != owner)
+ {
+ ch->gid = GMT_get_next_chid (t);
+ GML_channel_add (owner, lid_root, ch);
+ }
+ GMT_add_channel (t, ch);
+
+ return ch;
+}
+
+
+/**
+ * Handle a loopback message: call the appropriate handler for the message
type.
+ *
+ * @param ch Channel this message is on.
+ * @param msgh Message header.
+ * @param fwd Is this FWD traffic?
+ */
+void
+handle_loopback (struct CadetChannel *ch,
+ const struct GNUNET_MessageHeader *msgh,
+ int fwd)
+{
+ uint16_t type;
+
+ type = ntohs (msgh->type);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Loopback %s %s message!\n",
+ GM_f2s (fwd), GM_m2s (type));
+
+ switch (type)
+ {
+ case GNUNET_MESSAGE_TYPE_CADET_DATA:
+ /* Don't send hop ACK, wait for client to ACK */
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SEND loopback %u (%u)\n",
+ ntohl (((struct GNUNET_CADET_Data *) msgh)->mid), ntohs
(msgh->size));
+ GMCH_handle_data (ch, (struct GNUNET_CADET_Data *) msgh, fwd);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK:
+ GMCH_handle_data_ack (ch, (struct GNUNET_CADET_DataACK *) msgh, fwd);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE:
+ GMCH_handle_create (ch->t,
+ (struct GNUNET_CADET_ChannelCreate *) msgh);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK:
+ GMCH_handle_ack (ch,
+ (struct GNUNET_CADET_ChannelManage *) msgh,
+ fwd);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK:
+ GMCH_handle_nack (ch);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
+ GMCH_handle_destroy (ch,
+ (struct GNUNET_CADET_ChannelManage *) msgh,
+ fwd);
+ break;
+
+ default:
+ GNUNET_break_op (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "end-to-end message not known (%u)\n",
+ ntohs (msgh->type));
+ }
+}
+
+
+
+/******************************************************************************/
+/******************************** API
***********************************/
+/******************************************************************************/
+
+/**
+ * Destroy a channel and free all resources.
+ *
+ * @param ch Channel to destroy.
+ */
+void
+GMCH_destroy (struct CadetChannel *ch)
+{
+ struct CadetClient *c;
+ struct CadetTunnel3 *t;
+
+ if (NULL == ch)
+ return;
+ if (2 == ch->destroy)
+ return; /* recursive call */
+ ch->destroy = 2;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying channel %s:%u\n",
+ GMT_2s (ch->t), ch->gid);
+ GMCH_debug (ch);
+
+ c = ch->root;
+ if (NULL != c)
+ {
+ GML_channel_remove (c, ch->lid_root, ch);
+ }
+
+ c = ch->dest;
+ if (NULL != c)
+ {
+ GML_channel_remove (c, ch->lid_dest, ch);
+ }
+
+ channel_rel_free_all (ch->root_rel);
+ channel_rel_free_all (ch->dest_rel);
+
+ t = ch->t;
+ GMT_remove_channel (t, ch);
+ GNUNET_STATISTICS_update (stats, "# channels", -1, GNUNET_NO);
+
+ GNUNET_free (ch);
+ GMT_destroy_if_empty (t);
+}
+
+
+/**
+ * Get the channel's public ID.
+ *
+ * @param ch Channel.
+ *
+ * @return ID used to identify the channel with the remote peer.
+ */
+CADET_ChannelNumber
+GMCH_get_id (const struct CadetChannel *ch)
+{
+ return ch->gid;
+}
+
+
+/**
+ * Get the channel tunnel.
+ *
+ * @param ch Channel to get the tunnel from.
+ *
+ * @return tunnel of the channel.
+ */
+struct CadetTunnel3 *
+GMCH_get_tunnel (const struct CadetChannel *ch)
+{
+ return ch->t;
+}
+
+
+/**
+ * Get free buffer space towards the client on a specific channel.
+ *
+ * @param ch Channel.
+ * @param fwd Is query about FWD traffic?
+ *
+ * @return Free buffer space [0 - 64]
+ */
+unsigned int
+GMCH_get_buffer (struct CadetChannel *ch, int fwd)
+{
+ struct CadetChannelReliability *rel;
+
+ rel = fwd ? ch->dest_rel : ch->root_rel;
+
+ /* If rel is NULL it means that the end is not yet created,
+ * most probably is a loopback channel at the point of sending
+ * the ChannelCreate to itself.
+ */
+ if (NULL == rel)
+ return 64;
+
+ return (64 - rel->n_recv);
+}
+
+
+/**
+ * Get flow control status of end point: is client allow to send?
+ *
+ * @param ch Channel.
+ * @param fwd Is query about FWD traffic? (Request root status).
+ *
+ * @return #GNUNET_YES if client is allowed to send us data.
+ */
+int
+GMCH_get_allowed (struct CadetChannel *ch, int fwd)
+{
+ struct CadetChannelReliability *rel;
+
+ rel = fwd ? ch->root_rel : ch->dest_rel;
+
+ if (NULL == rel)
+ {
+ /* Probably shutting down: root/dest NULL'ed to mark disconnection */
+ GNUNET_break (GNUNET_NO != ch->destroy);
+ return 0;
+ }
+
+ return rel->client_allowed;
+}
+
+
+/**
+ * Is the root client for this channel on this peer?
+ *
+ * @param ch Channel.
+ * @param fwd Is this for fwd traffic?
+ *
+ * @return #GNUNET_YES in case it is.
+ */
+int
+GMCH_is_origin (struct CadetChannel *ch, int fwd)
+{
+ struct CadetClient *c;
+
+ c = fwd ? ch->root : ch->dest;
+ return NULL != c;
+}
+
+
+/**
+ * Is the destination client for this channel on this peer?
+ *
+ * @param ch Channel.
+ * @param fwd Is this for fwd traffic?
+ *
+ * @return #GNUNET_YES in case it is.
+ */
+int
+GMCH_is_terminal (struct CadetChannel *ch, int fwd)
+{
+ struct CadetClient *c;
+
+ c = fwd ? ch->dest : ch->root;
+ return NULL != c;
+}
+
+
+/**
+ * Send an end-to-end ACK message for the most recent in-sequence payload.
+ *
+ * If channel is not reliable, do nothing.
+ *
+ * @param ch Channel this is about.
+ * @param fwd Is for FWD traffic? (ACK dest->owner)
+ */
+void
+GMCH_send_data_ack (struct CadetChannel *ch, int fwd)
+{
+ struct GNUNET_CADET_DataACK msg;
+ struct CadetChannelReliability *rel;
+ struct CadetReliableMessage *copy;
+ unsigned int delta;
+ uint64_t mask;
+ uint32_t ack;
+
+ if (GNUNET_NO == ch->reliable)
+ {
+ return;
+ }
+ rel = fwd ? ch->dest_rel : ch->root_rel;
+ ack = rel->mid_recv - 1;
+ LOG (GNUNET_ERROR_TYPE_INFO, "===> DATA_ACK for %u\n", ack);
+
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_DATA_ACK);
+ msg.header.size = htons (sizeof (msg));
+ msg.chid = htonl (ch->gid);
+ msg.futures = 0;
+ for (copy = rel->head_recv; NULL != copy; copy = copy->next)
+ {
+ if (copy->type != GNUNET_MESSAGE_TYPE_CADET_DATA)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "!! Type %s, expected DATA\n",
+ GM_m2s (copy->type));
+ continue;
+ }
+ if (copy->mid == ack + 1)
+ {
+ ack++;
+ continue;
+ }
+ delta = copy->mid - (ack + 1);
+ if (63 < delta)
+ break;
+ mask = 0x1LL << delta;
+ msg.futures |= mask;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " !! setting bit for %u (delta %u) (%llX) -> %llX\n",
+ copy->mid, delta, mask, msg.futures);
+ }
+ msg.mid = htonl (ack);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "!!! ACK for %u, futures %llX\n",
+ ack, msg.futures);
+
+ GMCH_send_prebuilt_message (&msg.header, ch, !fwd, NULL);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "send_data_ack END\n");
+}
+
+
+/**
+ * Allow a client to send us more data, in case it was choked.
+ *
+ * @param ch Channel.
+ * @param fwd Is this about FWD traffic? (Root client).
+ */
+void
+GMCH_allow_client (struct CadetChannel *ch, int fwd)
+{
+ struct CadetChannelReliability *rel;
+ unsigned int buffer;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "GMCH allow\n");
+
+ if (CADET_CHANNEL_READY != ch->state)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " channel not ready yet!\n");
+ return;
+ }
+
+ if (GNUNET_YES == ch->reliable)
+ {
+ rel = fwd ? ch->root_rel : ch->dest_rel;
+ if (NULL == rel)
+ {
+ GNUNET_break (GNUNET_NO != ch->destroy);
+ return;
+ }
+ if (NULL != rel->head_sent)
+ {
+ if (64 <= rel->mid_send - rel->head_sent->mid)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " too big MID gap! Wait for ACK.\n");
+ return;
+ }
+ else
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " gap ok: %u - %u\n",
+ rel->head_sent->mid, rel->mid_send);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " head sent is NULL\n");
+ }
+ }
+
+ if (is_loopback (ch))
+ buffer = GMCH_get_buffer (ch, fwd);
+ else
+ buffer = GMT_get_connections_buffer (ch->t);
+
+ if (0 == buffer)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " no buffer space.\n");
+ return;
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space %u, allowing\n", buffer);
+ send_client_ack (ch, fwd);
+}
+
+
+/**
+ * Log channel info.
+ *
+ * @param ch Channel.
+ */
+void
+GMCH_debug (struct CadetChannel *ch)
+{
+ if (NULL == ch)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "*** DEBUG NULL CHANNEL ***\n");
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %s:%X (%p)\n",
+ GMT_2s (ch->t), ch->gid, ch);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " root %p/%p\n",
+ ch->root, ch->root_rel);
+ if (NULL != ch->root)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " cli %s\n", GML_2s (ch->root));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ready %s\n",
+ ch->root_rel->client_ready ? "YES" : "NO");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " id %X\n", ch->lid_root);
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " dest %p/%p\n",
+ ch->dest, ch->dest_rel);
+ if (NULL != ch->dest)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " cli %s\n", GML_2s (ch->dest));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ready %s\n",
+ ch->dest_rel->client_ready ? "YES" : "NO");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " id %X\n", ch->lid_dest);
+ }
+}
+
+
+/**
+ * Handle an ACK given by a client.
+ *
+ * Mark client as ready and send him any buffered data we could have for him.
+ *
+ * @param ch Channel.
+ * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by dest and go BCK)
+ */
+void
+GMCH_handle_local_ack (struct CadetChannel *ch, int fwd)
+{
+ struct CadetChannelReliability *rel;
+ struct CadetClient *c;
+
+ rel = fwd ? ch->dest_rel : ch->root_rel;
+ c = fwd ? ch->dest : ch->root;
+
+ rel->client_ready = GNUNET_YES;
+ send_client_buffered_data (ch, c, fwd);
+
+ if (GNUNET_YES == ch->destroy && 0 == rel->n_recv)
+ {
+ send_destroy (ch, GNUNET_YES);
+ GMCH_destroy (ch);
+ }
+ /* if loopback is marked for destruction, no need to ACK to the other peer,
+ * it requested the destruction and is already gone, therefore, else if.
+ */
+ else if (is_loopback (ch))
+ {
+ unsigned int buffer;
+
+ buffer = GMCH_get_buffer (ch, fwd);
+ if (0 < buffer)
+ GMCH_allow_client (ch, fwd);
+
+ return;
+ }
+ GMT_send_connection_acks (ch->t);
+}
+
+
+/**
+ * Handle data given by a client.
+ *
+ * Check whether the client is allowed to send in this tunnel, save if channel
+ * is reliable and send an ACK to the client if there is still buffer space
+ * in the tunnel.
+ *
+ * @param ch Channel.
+ * @param c Client which sent the data.
+ * @param message Message.
+ * @param fwd Is this a FWD data?
+ *
+ * @return GNUNET_OK if everything goes well, GNUNET_SYSERR in case of en
error.
+ */
+int
+GMCH_handle_local_data (struct CadetChannel *ch,
+ struct CadetClient *c,
+ struct GNUNET_MessageHeader *message,
+ int fwd)
+{
+ struct CadetChannelReliability *rel;
+ struct GNUNET_CADET_Data *payload;
+ size_t size = ntohs (message->size);
+ uint16_t p2p_size = sizeof(struct GNUNET_CADET_Data) + size;
+ unsigned char cbuf[p2p_size];
+
+ /* Is the client in the channel? */
+ if ( !( (fwd &&
+ ch->root == c)
+ ||
+ (!fwd &&
+ ch->dest == c) ) )
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ rel = fwd ? ch->root_rel : ch->dest_rel;
+
+ if (GNUNET_NO == rel->client_allowed)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ rel->client_allowed = GNUNET_NO;
+
+ /* Ok, everything is correct, send the message. */
+ payload = (struct GNUNET_CADET_Data *) cbuf;
+ payload->mid = htonl (rel->mid_send);
+ rel->mid_send++;
+ memcpy (&payload[1], message, size);
+ payload->header.size = htons (p2p_size);
+ payload->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_DATA);
+ payload->chid = htonl (ch->gid);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channel...\n");
+ GMCH_send_prebuilt_message (&payload->header, ch, fwd, NULL);
+
+ if (is_loopback (ch))
+ {
+ if (GMCH_get_buffer (ch, fwd) > 0)
+ GMCH_allow_client (ch, fwd);
+
+ return GNUNET_OK;
+ }
+
+ if (GMT_get_connections_buffer (ch->t) > 0)
+ {
+ GMCH_allow_client (ch, fwd);
+ }
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Handle a channel destroy requested by a client.
+ *
+ * Destroy the channel and the tunnel in case this was the last channel.
+ *
+ * @param ch Channel.
+ * @param c Client that requested the destruction (to avoid notifying him).
+ * @param is_root Is the request coming from root?
+ */
+void
+GMCH_handle_local_destroy (struct CadetChannel *ch,
+ struct CadetClient *c,
+ int is_root)
+{
+ ch->destroy = GNUNET_YES;
+ /* Cleanup after the tunnel */
+ if (GNUNET_NO == is_root && c == ch->dest)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is destination.\n", GML_2s (c));
+ GML_client_delete_channel (c, ch, ch->lid_dest);
+ ch->dest = NULL;
+ }
+ if (GNUNET_YES == is_root && c == ch->root)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is owner.\n", GML_2s (c));
+ GML_client_delete_channel (c, ch, ch->lid_root);
+ ch->root = NULL;
+ }
+
+ send_destroy (ch, GNUNET_NO);
+ if (0 == ch->pending_messages)
+ GMCH_destroy (ch);
+}
+
+
+/**
+ * Handle a channel create requested by a client.
+ *
+ * Create the channel and the tunnel in case this was the first0 channel.
+ *
+ * @param c Client that requested the creation (will be the root).
+ * @param msg Create Channel message.
+ *
+ * @return GNUNET_OK if everything went fine, GNUNET_SYSERR otherwise.
+ */
+int
+GMCH_handle_local_create (struct CadetClient *c,
+ struct GNUNET_CADET_ChannelMessage *msg)
+{
+ struct CadetChannel *ch;
+ struct CadetTunnel3 *t;
+ struct CadetPeer *peer;
+ CADET_ChannelNumber chid;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " towards %s:%u\n",
+ GNUNET_i2s (&msg->peer), ntohl (msg->port));
+ chid = ntohl (msg->channel_id);
+
+ /* Sanity check for duplicate channel IDs */
+ if (NULL != GML_channel_get (c, chid))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+
+ peer = GMP_get (&msg->peer);
+ GMP_add_tunnel (peer);
+ t = GMP_get_tunnel (peer);
+
+ if (GMP_get_short_id (peer) == myid)
+ {
+ GMT_change_cstate (t, CADET_TUNNEL3_READY);
+ }
+ else
+ {
+ /* FIXME change to a tunnel API, eliminate ch <-> peer connection */
+ GMP_connect (peer);
+ }
+
+ /* Create channel */
+ ch = channel_new (t, c, chid);
+ if (NULL == ch)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ ch->port = ntohl (msg->port);
+ channel_set_options (ch, ntohl (msg->opt));
+
+ /* In unreliable channels, we'll use the DLL to buffer BCK data */
+ ch->root_rel = GNUNET_new (struct CadetChannelReliability);
+ ch->root_rel->ch = ch;
+ ch->root_rel->retry_timer = CADET_RETRANSMIT_TIME;
+ ch->root_rel->expected_delay.rel_value_us = 0;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "CREATED CHANNEL %s\n", GMCH_2s (ch));
+
+ send_create (ch);
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Handler for cadet network payload traffic.
+ *
+ * @param ch Channel for the message.
+ * @param msg Unencryted data message.
+ * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
+ * #GNUNET_YES if message is FWD on the respective channel
(loopback)
+ * #GNUNET_NO if message is BCK on the respective channel (loopback)
+ * #GNUNET_SYSERR if message on a one-ended channel (remote)
+ */
+void
+GMCH_handle_data (struct CadetChannel *ch,
+ const struct GNUNET_CADET_Data *msg,
+ int fwd)
+{
+ struct CadetChannelReliability *rel;
+ struct CadetClient *c;
+ uint32_t mid;
+
+ /* If this is a remote (non-loopback) channel, find 'fwd'. */
+ if (GNUNET_SYSERR == fwd)
+ {
+ if (is_loopback (ch))
+ {
+ /* It is a loopback channel after all... */
+ GNUNET_break (0);
+ return;
+ }
+ fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO;
+ }
+
+ /* Initialize FWD/BCK data */
+ c = fwd ? ch->dest : ch->root;
+ rel = fwd ? ch->dest_rel : ch->root_rel;
+
+ if (NULL == c)
+ {
+ GNUNET_break (GNUNET_NO != ch->destroy);
+ return;
+ }
+
+ if (CADET_CHANNEL_READY != ch->state)
+ {
+ if (GNUNET_NO == fwd)
+ {
+ /* If we are the root, this means the other peer has sent traffic before
+ * receiving our ACK. Even if the SYNACK goes missing, no traffic should
+ * be sent before the ACK.
+ */
+ GNUNET_break_op (0);
+ return;
+ }
+ /* If we are the dest, this means that the SYNACK got to the root but
+ * the ACK went missing. Treat this as an ACK.
+ */
+ channel_confirm (ch, GNUNET_NO);
+ }
+
+ GNUNET_STATISTICS_update (stats, "# data received", 1, GNUNET_NO);
+
+ mid = ntohl (msg->mid);
+ LOG (GNUNET_ERROR_TYPE_INFO, "<=== DATA %u %s on channel %s\n",
+ mid, GM_f2s (fwd), GMCH_2s (ch));
+
+ if (GNUNET_NO == ch->reliable ||
+ ( !GM_is_pid_bigger (rel->mid_recv, mid) &&
+ GM_is_pid_bigger (rel->mid_recv + 64, mid) ) )
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "RECV %u (%u)\n",
+ mid, ntohs (msg->header.size));
+ if (GNUNET_YES == ch->reliable)
+ {
+ /* Is this the exact next expected messasge? */
+ if (mid == rel->mid_recv)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "as expected\n");
+ rel->mid_recv++;
+ send_client_data (ch, msg, fwd);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "save for later\n");
+ add_buffered_data (msg, rel);
+ }
+ }
+ else
+ {
+ /* Tunnel is unreliable: send to clients directly */
+ /* FIXME: accept Out Of Order traffic */
+ rel->mid_recv = mid + 1;
+ send_client_data (ch, msg, fwd);
+ }
+ }
+ else
+ {
+ GNUNET_break_op (GM_is_pid_bigger (rel->mid_recv, mid));
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "MID %u not expected (%u - %u), dropping!\n",
+ mid, rel->mid_recv, rel->mid_recv + 63);
+ }
+
+ GMCH_send_data_ack (ch, fwd);
+}
+
+
+/**
+ * Handler for cadet network traffic end-to-end ACKs.
+ *
+ * @param ch Channel on which we got this message.
+ * @param msg Data message.
+ * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
+ * #GNUNET_YES if message is FWD on the respective channel
(loopback)
+ * #GNUNET_NO if message is BCK on the respective channel (loopback)
+ * #GNUNET_SYSERR if message on a one-ended channel (remote)
+ */
+void
+GMCH_handle_data_ack (struct CadetChannel *ch,
+ const struct GNUNET_CADET_DataACK *msg,
+ int fwd)
+{
+ struct CadetChannelReliability *rel;
+ struct CadetReliableMessage *copy;
+ struct CadetReliableMessage *next;
+ uint32_t ack;
+ int work;
+
+ /* If this is a remote (non-loopback) channel, find 'fwd'. */
+ if (GNUNET_SYSERR == fwd)
+ {
+ if (is_loopback (ch))
+ {
+ /* It is a loopback channel after all... */
+ GNUNET_break (0);
+ return;
+ }
+ /* Inverted: if message came 'FWD' is a 'BCK ACK'. */
+ fwd = (NULL != ch->dest) ? GNUNET_NO : GNUNET_YES;
+ }
+
+ ack = ntohl (msg->mid);
+ LOG (GNUNET_ERROR_TYPE_INFO, "<=== %s ACK %u\n", GM_f2s (fwd), ack);
+
+ if (GNUNET_YES == fwd)
+ {
+ rel = ch->root_rel;
+ }
+ else
+ {
+ rel = ch->dest_rel;
+ }
+ if (NULL == rel)
+ {
+ GNUNET_break_op (GNUNET_NO != ch->destroy);
+ return;
+ }
+
+ /* Free ACK'd copies: no need to retransmit those anymore FIXME refactor */
+ for (work = GNUNET_NO, copy = rel->head_sent; copy != NULL; copy = next)
+ {
+ if (GM_is_pid_bigger (copy->mid, ack))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " head %u, out!\n", copy->mid);
+ channel_rel_free_sent (rel, msg);
+ break;
+ }
+ work = GNUNET_YES;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " id %u\n", copy->mid);
+ next = copy->next;
+ if (GNUNET_YES == rel_message_free (copy, GNUNET_YES))
+ return;
+ }
+
+ /* ACK client if needed and possible */
+ GMCH_allow_client (ch, fwd);
+
+ /* If some message was free'd, update the retransmission delay */
+ if (GNUNET_YES == work)
+ {
+ if (GNUNET_SCHEDULER_NO_TASK != rel->retry_task)
+ {
+ GNUNET_SCHEDULER_cancel (rel->retry_task);
+ rel->retry_task = GNUNET_SCHEDULER_NO_TASK;
+ if (NULL != rel->head_sent && NULL == rel->head_sent->chq)
+ {
+ struct GNUNET_TIME_Absolute new_target;
+ struct GNUNET_TIME_Relative delay;
+
+ delay = GNUNET_TIME_relative_multiply (rel->retry_timer,
+ CADET_RETRANSMIT_MARGIN);
+ new_target = GNUNET_TIME_absolute_add (rel->head_sent->timestamp,
+ delay);
+ delay = GNUNET_TIME_absolute_get_remaining (new_target);
+ rel->retry_task =
+ GNUNET_SCHEDULER_add_delayed (delay,
+ &channel_retransmit_message,
+ rel);
+ }
+ }
+ else
+ {
+ /* Work was done but no task was pending? Shouldn't happen! */
+ GNUNET_break (0);
+ }
+ }
+}
+
+
+/**
+ * Handler for channel create messages.
+ *
+ * Does not have fwd parameter because it's always 'FWD': channel is incoming.
+ *
+ * @param t Tunnel this channel will be in.
+ * @param msg Channel crate message.
+ */
+struct CadetChannel *
+GMCH_handle_create (struct CadetTunnel3 *t,
+ const struct GNUNET_CADET_ChannelCreate *msg)
+{
+ CADET_ChannelNumber chid;
+ struct CadetChannel *ch;
+ struct CadetClient *c;
+ int new_channel;
+ int reaction;
+
+ reaction = GNUNET_NO;
+ chid = ntohl (msg->chid);
+ ch = GMT_get_channel (t, chid);
+ if (NULL == ch)
+ {
+ /* Create channel */
+ ch = channel_new (t, NULL, 0);
+ ch->gid = chid;
+ channel_set_options (ch, ntohl (msg->opt));
+ new_channel = GNUNET_YES;
+ }
+ else
+ {
+ new_channel = GNUNET_NO;
+ }
+
+ if (GNUNET_YES == new_channel || GMT_is_loopback (t))
+ {
+ /* Find a destination client */
+ ch->port = ntohl (msg->port);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " port %u\n", ch->port);
+ c = GML_client_get_by_port (ch->port);
+ if (NULL == c)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " no client has port registered\n");
+ if (is_loopback (ch))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " loopback: destroy on handler\n");
+ send_nack (ch);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " not loopback: destroy now\n");
+ send_nack (ch);
+ GMCH_destroy (ch);
+ }
+ return NULL;
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " client %p has port registered\n", c);
+ }
+
+ add_destination (ch, c);
+ if (GNUNET_YES == ch->reliable)
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Reliable\n");
+ else
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Not Reliable\n");
+
+ send_client_create (ch);
+ ch->state = CADET_CHANNEL_SENT;
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate create channel\n");
+ reaction = GNUNET_YES;
+ if (GNUNET_SCHEDULER_NO_TASK != ch->dest_rel->retry_task)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " clearing retry task\n");
+ /* we were waiting to re-send our 'SYNACK', wait no more! */
+ GNUNET_SCHEDULER_cancel (ch->dest_rel->retry_task);
+ ch->dest_rel->retry_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ }
+ send_ack (ch, GNUNET_YES, reaction);
+
+ return ch;
+}
+
+
+/**
+ * Handler for channel NACK messages.
+ *
+ * NACK messages always go dest -> root, no need for 'fwd' or 'msg' parameter.
+ *
+ * @param ch Channel.
+ */
+void
+GMCH_handle_nack (struct CadetChannel *ch)
+{
+ send_client_nack (ch);
+ GMCH_destroy (ch);
+}
+
+
+/**
+ * Handler for channel ack messages.
+ *
+ * @param ch Channel.
+ * @param msg Message.
+ * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
+ * #GNUNET_YES if message is FWD on the respective channel
(loopback)
+ * #GNUNET_NO if message is BCK on the respective channel (loopback)
+ * #GNUNET_SYSERR if message on a one-ended channel (remote)
+ */
+void
+GMCH_handle_ack (struct CadetChannel *ch,
+ const struct GNUNET_CADET_ChannelManage *msg,
+ int fwd)
+{
+ /* If this is a remote (non-loopback) channel, find 'fwd'. */
+ if (GNUNET_SYSERR == fwd)
+ {
+ if (is_loopback (ch))
+ {
+ /* It is a loopback channel after all... */
+ GNUNET_break (0);
+ return;
+ }
+ fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO;
+ }
+
+ channel_confirm (ch, !fwd);
+}
+
+
+/**
+ * Handler for channel destroy messages.
+ *
+ * @param ch Channel to be destroyed of.
+ * @param msg Message.
+ * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
+ * #GNUNET_YES if message is FWD on the respective channel
(loopback)
+ * #GNUNET_NO if message is BCK on the respective channel (loopback)
+ * #GNUNET_SYSERR if message on a one-ended channel (remote)
+ */
+void
+GMCH_handle_destroy (struct CadetChannel *ch,
+ const struct GNUNET_CADET_ChannelManage *msg,
+ int fwd)
+{
+ struct CadetChannelReliability *rel;
+
+ /* If this is a remote (non-loopback) channel, find 'fwd'. */
+ if (GNUNET_SYSERR == fwd)
+ {
+ if (is_loopback (ch))
+ {
+ /* It is a loopback channel after all... */
+ GNUNET_break (0);
+ return;
+ }
+ fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO;
+ }
+
+ GMCH_debug (ch);
+ if ( (fwd && NULL == ch->dest) || (!fwd && NULL == ch->root) )
+ {
+ /* Not for us (don't destroy twice a half-open loopback channel) */
+ return;
+ }
+
+ rel = fwd ? ch->dest_rel : ch->root_rel;
+ if (0 == rel->n_recv)
+ {
+ send_destroy (ch, GNUNET_YES);
+ GMCH_destroy (ch);
+ }
+ else
+ {
+ ch->destroy = GNUNET_YES;
+ }
+}
+
+
+/**
+ * Sends an already built message on a channel.
+ *
+ * If the channel is on a loopback tunnel, notifies the appropriate destination
+ * client locally.
+ *
+ * On a normal channel passes the message to the tunnel for encryption and
+ * sending on a connection.
+ *
+ * This function DOES NOT save the message for retransmission.
+ *
+ * @param message Message to send. Function makes a copy of it.
+ * @param ch Channel on which this message is transmitted.
+ * @param fwd Is this a fwd message?
+ * @param existing_copy This is a retransmission, don't save a copy.
+ */
+void
+GMCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
+ struct CadetChannel *ch, int fwd,
+ void *existing_copy)
+{
+ struct CadetChannelQueue *chq;
+ uint16_t type;
+
+ type = ntohs (message->type);
+ LOG (GNUNET_ERROR_TYPE_INFO, "===> %s %s on channel %s\n",
+ GM_m2s (type), GM_f2s (fwd), GMCH_2s (ch));
+
+ if (GMT_is_loopback (ch->t))
+ {
+ handle_loopback (ch, message, fwd);
+ return;
+ }
+
+ switch (type)
+ {
+ struct GNUNET_CADET_Data *payload;
+ case GNUNET_MESSAGE_TYPE_CADET_DATA:
+
+ payload = (struct GNUNET_CADET_Data *) message;
+ LOG (GNUNET_ERROR_TYPE_INFO, "===> %s %u\n",
+ GM_m2s (type), ntohl (payload->mid));
+ if (GNUNET_YES == ch->reliable)
+ {
+ chq = GNUNET_new (struct CadetChannelQueue);
+ chq->type = type;
+ if (NULL == existing_copy)
+ chq->copy = channel_save_copy (ch, message, fwd);
+ else
+ {
+ chq->copy = (struct CadetReliableMessage *) existing_copy;
+ if (NULL != chq->copy->chq)
+ {
+ /* Last retransmission was queued but not yet sent!
+ * This retransmission was scheduled by a ch_message_sent which
+ * followed a very fast RTT, so the tiny delay made the
+ * retransmission function to execute before the previous
+ * retransmitted message even had a chance to leave the peer.
+ * Cancel this message and wait until the pending
+ * retransmission leaves the peer and ch_message_sent starts
+ * the timer for the next one.
+ */
+ GNUNET_free (chq);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " exisitng copy not yet transmitted!\n");
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " using existing copy: %p {r:%p q:%p t:%u}\n",
+ existing_copy,
+ chq->copy->rel, chq->copy->chq, chq->copy->type);
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " new chq: %p\n", chq);
+ chq->copy->chq = chq;
+ chq->tq = GMT_send_prebuilt_message (message, ch->t, NULL,
+ NULL != existing_copy,
+ &ch_message_sent, chq);
+ /* q itself is stored in copy */
+ GNUNET_assert (NULL != chq->tq || GNUNET_NO != ch->destroy);
+ }
+ else
+ {
+ fire_and_forget (message, ch, GNUNET_NO);
+ }
+ break;
+
+
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK:
+ if (GNUNET_YES == fwd || NULL != existing_copy)
+ {
+ /* BCK ACK (going FWD) is just a response for a SYNACK, don't keep*/
+ fire_and_forget (message, ch, GNUNET_YES);
+ return;
+ }
+ /* fall-trough */
+ case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK:
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE:
+ chq = GNUNET_new (struct CadetChannelQueue);
+ chq->type = type;
+ chq->rel = fwd ? ch->root_rel : ch->dest_rel;
+ if (NULL != chq->rel->uniq)
+ {
+ if (NULL != chq->rel->uniq->tq)
+ {
+ GMT_cancel (chq->rel->uniq->tq);
+ /* ch_message_sent is called, freeing and NULLing uniq */
+ }
+ else
+ {
+ GNUNET_break (0);
+ GNUNET_free (chq->rel->uniq);
+ }
+ }
+ chq->tq = GMT_send_prebuilt_message (message, ch->t, NULL, GNUNET_YES,
+ &ch_message_sent, chq);
+ if (NULL == chq->tq)
+ {
+ GNUNET_break (0);
+ GNUNET_free (chq);
+ chq = NULL;
+ return;
+ }
+ chq->rel->uniq = chq;
+ break;
+
+
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK:
+ fire_and_forget (message, ch, GNUNET_YES);
+ break;
+
+
+ default:
+ GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "type %s unknown!\n", GM_m2s (type));
+ fire_and_forget (message, ch, GNUNET_YES);
+ }
+}
+
+
+/**
+ * Get the static string for identification of the channel.
+ *
+ * @param ch Channel.
+ *
+ * @return Static string with the channel IDs.
+ */
+const char *
+GMCH_2s (const struct CadetChannel *ch)
+{
+ static char buf[64];
+
+ if (NULL == ch)
+ return "(NULL Channel)";
+
+ sprintf (buf, "%s:%u gid:%X (%X / %X)",
+ GMT_2s (ch->t), ch->port, ch->gid, ch->lid_root, ch->lid_dest);
+
+ return buf;
+}
Copied: gnunet/src/cadet/gnunet-service-cadet_channel.h (from rev 33185,
gnunet/src/mesh/gnunet-service-cadet_channel.h)
===================================================================
--- gnunet/src/cadet/gnunet-service-cadet_channel.h
(rev 0)
+++ gnunet/src/cadet/gnunet-service-cadet_channel.h 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -0,0 +1,349 @@
+/*
+ This file is part of GNUnet.
+ (C) 2013 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_channel.h
+ * @brief cadet service; dealing with end-to-end channels
+ * @author Bartlomiej Polot
+ *
+ * All functions in this file should use the prefix GMCH (Gnunet Cadet CHannel)
+ */
+
+#ifndef GNUNET_SERVICE_CADET_CHANNEL_H
+#define GNUNET_SERVICE_CADET_CHANNEL_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0 /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+#include "cadet_protocol.h"
+#include "cadet.h"
+
+/**
+ * Struct containing all information regarding a channel to a remote client.
+ */
+struct CadetChannel;
+
+
+#include "gnunet-service-cadet_tunnel.h"
+#include "gnunet-service-cadet_local.h"
+
+
+/**
+ * Destroy a channel and free all resources.
+ *
+ * @param ch Channel to destroy.
+ */
+void
+GMCH_destroy (struct CadetChannel *ch);
+
+
+/**
+ * Get the channel's public ID.
+ *
+ * @param ch Channel.
+ *
+ * @return ID used to identify the channel with the remote peer.
+ */
+CADET_ChannelNumber
+GMCH_get_id (const struct CadetChannel *ch);
+
+/**
+ * Get the channel tunnel.
+ *
+ * @param ch Channel to get the tunnel from.
+ *
+ * @return tunnel of the channel.
+ */
+struct CadetTunnel3 *
+GMCH_get_tunnel (const struct CadetChannel *ch);
+
+/**
+ * Get free buffer space towards the client on a specific channel.
+ *
+ * @param ch Channel.
+ * @param fwd Is query about FWD traffic?
+ *
+ * @return Free buffer space [0 - 64]
+ */
+unsigned int
+GMCH_get_buffer (struct CadetChannel *ch, int fwd);
+
+
+/**
+ * Get flow control status of end point: is client allow to send?
+ *
+ * @param ch Channel.
+ * @param fwd Is query about FWD traffic? (Request root status).
+ *
+ * @return #GNUNET_YES if client is allowed to send us data.
+ */
+int
+GMCH_get_allowed (struct CadetChannel *ch, int fwd);
+
+
+/**
+ * Is the root client for this channel on this peer?
+ *
+ * @param ch Channel.
+ * @param fwd Is this for fwd traffic?
+ *
+ * @return #GNUNET_YES in case it is.
+ */
+int
+GMCH_is_origin (struct CadetChannel *ch, int fwd);
+
+/**
+ * Is the destination client for this channel on this peer?
+ *
+ * @param ch Channel.
+ * @param fwd Is this for fwd traffic?
+ *
+ * @return #GNUNET_YES in case it is.
+ */
+int
+GMCH_is_terminal (struct CadetChannel *ch, int fwd);
+
+/**
+ * Send an end-to-end ACK message for the most recent in-sequence payload.
+ *
+ * If channel is not reliable, do nothing.
+ *
+ * @param ch Channel this is about.
+ * @param fwd Is for FWD traffic? (ACK dest->owner)
+ */
+void
+GMCH_send_data_ack (struct CadetChannel *ch, int fwd);
+
+/**
+ * Notify the destination client that a new incoming channel was created.
+ *
+ * @param ch Channel that was created.
+ */
+void
+GMCH_send_create (struct CadetChannel *ch);
+
+/**
+ * Allow a client to send us more data, in case it was choked.
+ *
+ * @param ch Channel.
+ * @param fwd Is this about FWD traffic? (Root client).
+ */
+void
+GMCH_allow_client (struct CadetChannel *ch, int fwd);
+
+/**
+ * Log channel info.
+ *
+ * @param ch Channel.
+ */
+void
+GMCH_debug (struct CadetChannel *ch);
+
+/**
+ * Handle an ACK given by a client.
+ *
+ * Mark client as ready and send him any buffered data we could have for him.
+ *
+ * @param ch Channel.
+ * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by root and go BCK)
+ */
+void
+GMCH_handle_local_ack (struct CadetChannel *ch, int fwd);
+
+/**
+ * Handle data given by a client.
+ *
+ * Check whether the client is allowed to send in this tunnel, save if channel
+ * is reliable and send an ACK to the client if there is still buffer space
+ * in the tunnel.
+ *
+ * @param ch Channel.
+ * @param c Client which sent the data.
+ * @param message Message.
+ * @param fwd Is this a FWD data?
+ *
+ * @return GNUNET_OK if everything goes well, GNUNET_SYSERR in case of en
error.
+ */
+int
+GMCH_handle_local_data (struct CadetChannel *ch,
+ struct CadetClient *c,
+ struct GNUNET_MessageHeader *message,
+ int fwd);
+
+/**
+ * Handle a channel destroy requested by a client.
+ *
+ * Destroy the channel and the tunnel in case this was the last channel.
+ *
+ * @param ch Channel.
+ * @param c Client that requested the destruction (to avoid notifying him).
+ * @param is_root Is the request coming from root?
+ */
+void
+GMCH_handle_local_destroy (struct CadetChannel *ch,
+ struct CadetClient *c,
+ int is_root);
+
+/**
+ * Handle a channel create requested by a client.
+ *
+ * Create the channel and the tunnel in case this was the first0 channel.
+ *
+ * @param c Client that requested the creation (will be the root).
+ * @param msg Create Channel message.
+ *
+ * @return GNUNET_OK if everything went fine, GNUNET_SYSERR otherwise.
+ */
+int
+GMCH_handle_local_create (struct CadetClient *c,
+ struct GNUNET_CADET_ChannelMessage *msg);
+
+/**
+ * Handler for cadet network payload traffic.
+ *
+ * @param ch Channel for the message.
+ * @param msg Unencryted data message.
+ * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
+ * #GNUNET_YES if message is FWD on the respective channel
(loopback)
+ * #GNUNET_NO if message is BCK on the respective channel (loopback)
+ * #GNUNET_SYSERR if message on a one-ended channel (remote)
+ */
+void
+GMCH_handle_data (struct CadetChannel *ch,
+ const struct GNUNET_CADET_Data *msg,
+ int fwd);
+
+/**
+ * Handler for cadet network traffic end-to-end ACKs.
+ *
+ * @param ch Channel on which we got this message.
+ * @param msg Data message.
+ * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
+ * #GNUNET_YES if message is FWD on the respective channel
(loopback)
+ * #GNUNET_NO if message is BCK on the respective channel (loopback)
+ * #GNUNET_SYSERR if message on a one-ended channel (remote)
+ */
+void
+GMCH_handle_data_ack (struct CadetChannel *ch,
+ const struct GNUNET_CADET_DataACK *msg,
+ int fwd);
+
+/**
+ * Handler for channel create messages.
+ *
+ * Does not have fwd parameter because it's always 'FWD': channel is incoming.
+ *
+ * @param t Tunnel this channel will be in.
+ * @param msg Channel crate message.
+ */
+struct CadetChannel *
+GMCH_handle_create (struct CadetTunnel3 *t,
+ const struct GNUNET_CADET_ChannelCreate *msg);
+
+/**
+ * Handler for channel NACK messages.
+ *
+ * NACK messages always go dest -> root, no need for 'fwd' or 'msg' parameter.
+ *
+ * @param ch Channel.
+ */
+void
+GMCH_handle_nack (struct CadetChannel *ch);
+
+/**
+ * Handler for channel ack messages.
+ *
+ * @param ch Channel this channel is to be created in.
+ * @param msg Message.
+ * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
+ * #GNUNET_YES if message is FWD on the respective channel
(loopback)
+ * #GNUNET_NO if message is BCK on the respective channel (loopback)
+ * #GNUNET_SYSERR if message on a one-ended channel (remote)
+ */
+void
+GMCH_handle_ack (struct CadetChannel *ch,
+ const struct GNUNET_CADET_ChannelManage *msg,
+ int fwd);
+
+/**
+ * Handler for channel destroy messages.
+ *
+ * @param ch Channel this channel is to be destroyed of.
+ * @param msg Message.
+ * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
+ * #GNUNET_YES if message is FWD on the respective channel
(loopback)
+ * #GNUNET_NO if message is BCK on the respective channel (loopback)
+ * #GNUNET_SYSERR if message on a one-ended channel (remote)
+ */
+void
+GMCH_handle_destroy (struct CadetChannel *ch,
+ const struct GNUNET_CADET_ChannelManage *msg,
+ int fwd);
+
+/**
+ * Sends an already built message on a channel.
+ *
+ * If the channel is on a loopback tunnel, notifies the appropriate destination
+ * client locally.
+ *
+ * On a normal channel passes the message to the tunnel for encryption and
+ * sending on a connection.
+ *
+ * This function DOES NOT save the message for retransmission.
+ *
+ * @param message Message to send. Function makes a copy of it.
+ * @param ch Channel on which this message is transmitted.
+ * @param fwd Is this a fwd message?
+ * @param existing_copy This is a retransmission, don't save a copy.
+ */
+void
+GMCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
+ struct CadetChannel *ch, int fwd,
+ void *existing_copy);
+
+/**
+ * Get the static string for identification of the channel.
+ *
+ * @param ch Channel.i
+ *
+ * @return Static string with the channel IDs.
+ */
+const char *
+GMCH_2s (const struct CadetChannel *ch);
+
+
+#if 0 /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* ifndef GNUNET_SERVICE_CADET_CHANNEL_H */
+#endif
+/* end of gnunet-service-cadet_channel.h */
Copied: gnunet/src/cadet/gnunet-service-cadet_connection.c (from rev 33185,
gnunet/src/mesh/gnunet-service-cadet_connection.c)
===================================================================
--- gnunet/src/cadet/gnunet-service-cadet_connection.c
(rev 0)
+++ gnunet/src/cadet/gnunet-service-cadet_connection.c 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -0,0 +1,3176 @@
+/*
+ This file is part of GNUnet.
+ (C) 2001-2013 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_connection.c
+ * @brief GNUnet CADET service connection handling
+ * @author Bartlomiej Polot
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+#include "gnunet_statistics_service.h"
+
+#include "cadet_path.h"
+#include "cadet_protocol.h"
+#include "cadet.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_tunnel.h"
+
+
+#define LOG(level, ...) GNUNET_log_from (level,"cadet-con",__VA_ARGS__)
+
+#define CADET_MAX_POLL_TIME GNUNET_TIME_relative_multiply (\
+ GNUNET_TIME_UNIT_MINUTES,\
+ 10)
+#define AVG_MSGS 32
+
+
+/******************************************************************************/
+/******************************** STRUCTS
**********************************/
+/******************************************************************************/
+
+/**
+ * Struct to encapsulate all the Flow Control information to a peer to which
+ * we are directly connected (on a core level).
+ */
+struct CadetFlowControl
+{
+ /**
+ * Connection this controls.
+ */
+ struct CadetConnection *c;
+
+ /**
+ * How many messages are in the queue on this connection.
+ */
+ unsigned int queue_n;
+
+ /**
+ * How many messages do we accept in the queue.
+ */
+ unsigned int queue_max;
+
+ /**
+ * ID of the last packet sent towards the peer.
+ */
+ uint32_t last_pid_sent;
+
+ /**
+ * ID of the last packet received from the peer.
+ */
+ uint32_t last_pid_recv;
+
+ /**
+ * Last ACK sent to the peer (peer can't send more than this PID).
+ */
+ uint32_t last_ack_sent;
+
+ /**
+ * Last ACK sent towards the origin (for traffic towards leaf node).
+ */
+ uint32_t last_ack_recv;
+
+ /**
+ * Task to poll the peer in case of a lost ACK causes stall.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier poll_task;
+
+ /**
+ * How frequently to poll for ACKs.
+ */
+ struct GNUNET_TIME_Relative poll_time;
+
+ /**
+ * Queued poll message, to cancel if not necessary anymore (got ACK).
+ */
+ struct CadetConnectionQueue *poll_msg;
+
+ /**
+ * Queued poll message, to cancel if not necessary anymore (got ACK).
+ */
+ struct CadetConnectionQueue *ack_msg;
+};
+
+/**
+ * Keep a record of the last messages sent on this connection.
+ */
+struct CadetConnectionPerformance
+{
+ /**
+ * Circular buffer for storing measurements.
+ */
+ double usecsperbyte[AVG_MSGS];
+
+ /**
+ * Running average of @c usecsperbyte.
+ */
+ double avg;
+
+ /**
+ * How many values of @c usecsperbyte are valid.
+ */
+ uint16_t size;
+
+ /**
+ * Index of the next "free" position in @c usecsperbyte.
+ */
+ uint16_t idx;
+};
+
+
+/**
+ * Struct containing all information regarding a connection to a peer.
+ */
+struct CadetConnection
+{
+ /**
+ * Tunnel this connection is part of.
+ */
+ struct CadetTunnel3 *t;
+
+ /**
+ * Flow control information for traffic fwd.
+ */
+ struct CadetFlowControl fwd_fc;
+
+ /**
+ * Flow control information for traffic bck.
+ */
+ struct CadetFlowControl bck_fc;
+
+ /**
+ * Measure connection performance on the endpoint.
+ */
+ struct CadetConnectionPerformance *perf;
+
+ /**
+ * ID of the connection.
+ */
+ struct GNUNET_CADET_Hash id;
+
+ /**
+ * State of the connection.
+ */
+ enum CadetConnectionState state;
+
+ /**
+ * Path being used for the tunnel. At the origin of the connection
+ * it's a pointer to the destination's path pool, otherwise just a copy.
+ */
+ struct CadetPeerPath *path;
+
+ /**
+ * Position of the local peer in the path.
+ */
+ unsigned int own_pos;
+
+ /**
+ * Task to keep the used paths alive at the owner,
+ * time tunnel out on all the other peers.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier fwd_maintenance_task;
+
+ /**
+ * Task to keep the used paths alive at the destination,
+ * time tunnel out on all the other peers.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier bck_maintenance_task;
+
+ /**
+ * Queue handle for maintainance traffic. One handle for FWD and BCK since
+ * one peer never needs to maintain both directions (no loopback
connections).
+ */
+ struct CadetPeerQueue *maintenance_q;
+
+ /**
+ * Counter to do exponential backoff when creating a connection (max 64).
+ */
+ unsigned short create_retry;
+
+ /**
+ * Pending message count.
+ */
+ int pending_messages;
+
+ /**
+ * Destroy flag: if true, destroy on last message.
+ */
+ int destroy;
+};
+
+/**
+ * Handle for messages queued but not yet sent.
+ */
+struct CadetConnectionQueue
+{
+ /**
+ * Peer queue handle, to cancel if necessary.
+ */
+ struct CadetPeerQueue *q;
+
+ /**
+ * Was this a forced message? (Do not account for it)
+ */
+ int forced;
+
+ /**
+ * Continuation to call once sent.
+ */
+ GMC_sent cont;
+
+ /**
+ * Closure for @c cont.
+ */
+ void *cont_cls;
+};
+
+/******************************************************************************/
+/******************************* GLOBALS
***********************************/
+/******************************************************************************/
+
+/**
+ * Global handle to the statistics service.
+ */
+extern struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Local peer own ID (memory efficient handle).
+ */
+extern GNUNET_PEER_Id myid;
+
+/**
+ * Local peer own ID (full value).
+ */
+extern struct GNUNET_PeerIdentity my_full_id;
+
+/**
+ * Connections known, indexed by cid (CadetConnection).
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *connections;
+
+/**
+ * How many connections are we willing to maintain.
+ * Local connections are always allowed, even if there are more connections
than max.
+ */
+static unsigned long long max_connections;
+
+/**
+ * How many messages *in total* are we willing to queue, divide by number of
+ * connections to get connection queue size.
+ */
+static unsigned long long max_msgs_queue;
+
+/**
+ * How often to send path keepalives. Paths timeout after 4 missed.
+ */
+static struct GNUNET_TIME_Relative refresh_connection_time;
+
+/**
+ * How often to send path create / ACKs.
+ */
+static struct GNUNET_TIME_Relative create_connection_time;
+
+
+/******************************************************************************/
+/******************************** STATIC
***********************************/
+/******************************************************************************/
+
+#if 0 // avoid compiler warning for unused static function
+static void
+fc_debug (struct CadetFlowControl *fc)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " IN: %u/%u\n",
+ fc->last_pid_recv, fc->last_ack_sent);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " OUT: %u/%u\n",
+ fc->last_pid_sent, fc->last_ack_recv);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " QUEUE: %u/%u\n",
+ fc->queue_n, fc->queue_max);
+}
+
+static void
+connection_debug (struct CadetConnection *c)
+{
+ if (NULL == c)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "*** DEBUG NULL CONNECTION ***\n");
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s:%X\n",
+ peer2s (c->t->peer), GMC_2s (c));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " state: %u, pending msgs: %u\n",
+ c->state, c->pending_messages);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD FC\n");
+ fc_debug (&c->fwd_fc);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK FC\n");
+ fc_debug (&c->bck_fc);
+}
+#endif
+
+
+/**
+ * Schedule next keepalive task, taking in consideration
+ * the connection state and number of retries.
+ *
+ * @param c Connection for which to schedule the next keepalive.
+ * @param fwd Direction for the next keepalive.
+ */
+static void
+schedule_next_keepalive (struct CadetConnection *c, int fwd);
+
+
+/**
+ * Resets the connection timeout task, some other message has done the
+ * task's job.
+ * - For the first peer on the direction this means to send
+ * a keepalive or a path confirmation message (either create or ACK).
+ * - For all other peers, this means to destroy the connection,
+ * due to lack of activity.
+ * Starts the timeout if no timeout was running (connection just created).
+ *
+ * @param c Connection whose timeout to reset.
+ * @param fwd Is this forward?
+ */
+static void
+connection_reset_timeout (struct CadetConnection *c, int fwd);
+
+
+/**
+ * Get string description for tunnel state. Reentrant.
+ *
+ * @param s Tunnel state.
+ *
+ * @return String representation.
+ */
+static const char *
+GMC_state2s (enum CadetConnectionState s)
+{
+ switch (s)
+ {
+ case CADET_CONNECTION_NEW:
+ return "CADET_CONNECTION_NEW";
+ case CADET_CONNECTION_SENT:
+ return "CADET_CONNECTION_SENT";
+ case CADET_CONNECTION_ACK:
+ return "CADET_CONNECTION_ACK";
+ case CADET_CONNECTION_READY:
+ return "CADET_CONNECTION_READY";
+ case CADET_CONNECTION_DESTROYED:
+ return "CADET_CONNECTION_DESTROYED";
+ default:
+ return "CADET_CONNECTION_STATE_ERROR";
+ }
+}
+
+
+/**
+ * Initialize a Flow Control structure to the initial state.
+ *
+ * @param fc Flow Control structure to initialize.
+ */
+static void
+fc_init (struct CadetFlowControl *fc)
+{
+ fc->last_pid_sent = (uint32_t) -1; /* Next (expected) = 0 */
+ fc->last_pid_recv = (uint32_t) -1;
+ fc->last_ack_sent = (uint32_t) 0;
+ fc->last_ack_recv = (uint32_t) 0;
+ fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
+ fc->poll_time = GNUNET_TIME_UNIT_SECONDS;
+ fc->queue_n = 0;
+ fc->queue_max = (max_msgs_queue / max_connections) + 1;
+}
+
+
+/**
+ * Find a connection.
+ *
+ * @param cid Connection ID.
+ */
+static struct CadetConnection *
+connection_get (const struct GNUNET_CADET_Hash *cid)
+{
+ return GNUNET_CONTAINER_multihashmap_get (connections, GM_h2hc (cid));
+}
+
+
+static void
+connection_change_state (struct CadetConnection* c,
+ enum CadetConnectionState state)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Connection %s state %s -> %s\n",
+ GMC_2s (c), GMC_state2s (c->state), GMC_state2s (state));
+ if (CADET_CONNECTION_DESTROYED == c->state)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "state not changing anymore\n");
+ return;
+ }
+ c->state = state;
+ if (CADET_CONNECTION_READY == state)
+ c->create_retry = 1;
+}
+
+
+/**
+ * Callback called when a queued ACK message is sent.
+ *
+ * @param cls Closure (FC).
+ * @param c Connection this message was on.
+ * @param q Queue handler this call invalidates.
+ * @param type Type of message sent.
+ * @param fwd Was this a FWD going message?
+ * @param size Size of the message.
+ */
+static void
+ack_sent (void *cls,
+ struct CadetConnection *c,
+ struct CadetConnectionQueue *q,
+ uint16_t type, int fwd, size_t size)
+{
+ struct CadetFlowControl *fc = cls;
+
+ fc->ack_msg = NULL;
+}
+
+
+/**
+ * Send an ACK on the connection, informing the predecessor about
+ * the available buffer space. Should not be called in case the peer
+ * is origin (no predecessor) in the @c fwd direction.
+ *
+ * Note that for fwd ack, the FWD mean forward *traffic* (root->dest),
+ * the ACK itself goes "back" (dest->root).
+ *
+ * @param c Connection on which to send the ACK.
+ * @param buffer How much space free to advertise?
+ * @param fwd Is this FWD ACK? (Going dest -> root)
+ * @param force Don't optimize out.
+ */
+static void
+send_ack (struct CadetConnection *c, unsigned int buffer, int fwd, int force)
+{
+ struct CadetFlowControl *next_fc;
+ struct CadetFlowControl *prev_fc;
+ struct GNUNET_CADET_ACK msg;
+ uint32_t ack;
+ int delta;
+
+ /* If origin, there is no connection to send ACKs. Wrong function! */
+ if (GMC_is_origin (c, fwd))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "connection %s is origin in %s\n",
+ GMC_2s (c), GM_f2s (fwd));
+ GNUNET_break (0);
+ return;
+ }
+
+ next_fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ prev_fc = fwd ? &c->bck_fc : &c->fwd_fc;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "connection send %s ack on %s\n",
+ GM_f2s (fwd), GMC_2s (c));
+
+ /* Check if we need to transmit the ACK. */
+ delta = prev_fc->last_ack_sent - prev_fc->last_pid_recv;
+ if (3 < delta && buffer < delta && GNUNET_NO == force)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending ACK, buffer > 3\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " last pid recv: %u, last ack sent: %u\n",
+ prev_fc->last_pid_recv, prev_fc->last_ack_sent);
+ return;
+ }
+
+ /* Ok, ACK might be necessary, what PID to ACK? */
+ ack = prev_fc->last_pid_recv + buffer;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ACK %u\n", ack);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " last pid %u, last ack %u, qmax %u, q %u\n",
+ prev_fc->last_pid_recv, prev_fc->last_ack_sent,
+ next_fc->queue_max, next_fc->queue_n);
+ if (ack == prev_fc->last_ack_sent && GNUNET_NO == force)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending FWD ACK, not needed\n");
+ return;
+ }
+
+ /* Check if message is already in queue */
+ if (NULL != prev_fc->ack_msg)
+ {
+ if (GM_is_pid_bigger (ack, prev_fc->last_ack_sent))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " canceling old ACK\n");
+ GMC_cancel (prev_fc->ack_msg);
+ /* GMC_cancel triggers ack_sent(), which clears fc->ack_msg */
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " same ACK already in queue\n");
+ return;
+ }
+ }
+
+ prev_fc->last_ack_sent = ack;
+
+ /* Build ACK message and send on connection */
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_ACK);
+ msg.ack = htonl (ack);
+ msg.cid = c->id;
+
+ prev_fc->ack_msg = GMC_send_prebuilt_message (&msg.header,
+ GNUNET_MESSAGE_TYPE_CADET_ACK,
+ ack, c, !fwd, GNUNET_YES,
+ &ack_sent, prev_fc);
+}
+
+
+/**
+ * Callback called when a connection queued message is sent.
+ *
+ * Calculates the average time and connection packet tracking.
+ *
+ * @param cls Closure (ConnectionQueue Handle).
+ * @param c Connection this message was on.
+ * @param sent Was it really sent? (Could have been canceled)
+ * @param type Type of message sent.
+ * @param pid Packet ID, or 0 if not applicable (create, destroy, etc).
+ * @param fwd Was this a FWD going message?
+ * @param size Size of the message.
+ * @param wait Time spent waiting for core (only the time for THIS message)
+ */
+static void
+conn_message_sent (void *cls,
+ struct CadetConnection *c, int sent,
+ uint16_t type, uint32_t pid, int fwd, size_t size,
+ struct GNUNET_TIME_Relative wait)
+{
+ struct CadetConnectionPerformance *p;
+ struct CadetFlowControl *fc;
+ struct CadetConnectionQueue *q = cls;
+ double usecsperbyte;
+ int forced;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "connection message_sent\n");
+
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " %ssent %s %s\n",
+ sent ? "" : "not ", GM_f2s (fwd), GM_m2s (type));
+ if (NULL != q)
+ {
+ forced = q->forced;
+ if (NULL != q->cont)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " calling cont\n");
+ q->cont (q->cont_cls, c, q, type, fwd, size);
+ }
+ GNUNET_free (q);
+ }
+ else if (type == GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED)
+ {
+ /* If NULL == q and ENCRYPTED == type, message must have been ch_mngmnt */
+ forced = GNUNET_YES;
+ }
+ else
+ {
+ forced = GNUNET_NO;
+ }
+ if (NULL == c)
+ {
+ GNUNET_break (type == GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN ||
+ type == GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);
+ LOG (GNUNET_ERROR_TYPE_ERROR, "Message %s sent on NULL connection!\n",
+ GM_m2s (type));
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P- %p %u\n", c, c->pending_messages);
+ c->pending_messages--;
+ if (GNUNET_YES == c->destroy && 0 == c->pending_messages)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "! destroying connection!\n");
+ GMC_destroy (c);
+ return;
+ }
+ /* Send ACK if needed, after accounting for sent ID in fc->queue_n */
+ switch (type)
+ {
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK:
+ c->maintenance_q = NULL;
+ /* Don't trigger a keepalive for sent ACKs, only SYN and SYNACKs */
+ if (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE == type || !fwd)
+ schedule_next_keepalive (c, fwd);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
+ if (GNUNET_YES == sent)
+ {
+ GNUNET_assert (NULL != q);
+ fc->last_pid_sent = pid; // FIXME
+ GMC_send_ack (c, fwd, GNUNET_NO);
+ connection_reset_timeout (c, fwd);
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "! Q_N- %p %u\n", fc, fc->queue_n);
+ if (GNUNET_NO == forced)
+ {
+ fc->queue_n--;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "! accounting pid %u\n",
+ fc->last_pid_sent);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "! forced, Q_N not accounting pid %u\n",
+ fc->last_pid_sent);
+ }
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_KX:
+ if (GNUNET_YES == sent)
+ connection_reset_timeout (c, fwd);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_POLL:
+ fc->poll_msg = NULL;
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_ACK:
+ fc->ack_msg = NULL;
+ break;
+
+ default:
+ break;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "! message sent!\n");
+
+ if (NULL == c->perf)
+ return; /* Only endpoints are interested in timing. */
+
+ p = c->perf;
+ usecsperbyte = ((double) wait.rel_value_us) / size;
+ if (p->size == AVG_MSGS)
+ {
+ /* Array is full. Substract oldest value, add new one and store. */
+ p->avg -= (p->usecsperbyte[p->idx] / AVG_MSGS);
+ p->usecsperbyte[p->idx] = usecsperbyte;
+ p->avg += (p->usecsperbyte[p->idx] / AVG_MSGS);
+ }
+ else
+ {
+ /* Array not yet full. Add current value to avg and store. */
+ p->usecsperbyte[p->idx] = usecsperbyte;
+ p->avg *= p->size;
+ p->avg += p->usecsperbyte[p->idx];
+ p->size++;
+ p->avg /= p->size;
+ }
+ p->idx = (p->idx + 1) % AVG_MSGS;
+}
+
+
+/**
+ * Get the previous hop in a connection
+ *
+ * @param c Connection.
+ *
+ * @return Previous peer in the connection.
+ */
+static struct CadetPeer *
+get_prev_hop (const struct CadetConnection *c)
+{
+ GNUNET_PEER_Id id;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " get prev hop %s [%u/%u]\n",
+ GMC_2s (c), c->own_pos, c->path->length);
+ if (0 == c->own_pos || c->path->length < 2)
+ id = c->path->peers[0];
+ else
+ id = c->path->peers[c->own_pos - 1];
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ID: %s (%u)\n",
+ GNUNET_i2s (GNUNET_PEER_resolve2 (id)), id);
+
+ return GMP_get_short (id);
+}
+
+
+/**
+ * Get the next hop in a connection
+ *
+ * @param c Connection.
+ *
+ * @return Next peer in the connection.
+ */
+static struct CadetPeer *
+get_next_hop (const struct CadetConnection *c)
+{
+ GNUNET_PEER_Id id;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " get next hop %s [%u/%u]\n",
+ GMC_2s (c), c->own_pos, c->path->length);
+ if ((c->path->length - 1) == c->own_pos || c->path->length < 2)
+ id = c->path->peers[c->path->length - 1];
+ else
+ id = c->path->peers[c->own_pos + 1];
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ID: %s (%u)\n",
+ GNUNET_i2s (GNUNET_PEER_resolve2 (id)), id);
+
+ return GMP_get_short (id);
+}
+
+
+/**
+ * Get the hop in a connection.
+ *
+ * @param c Connection.
+ * @param fwd Next hop?
+ *
+ * @return Next peer in the connection.
+ */
+static struct CadetPeer *
+get_hop (struct CadetConnection *c, int fwd)
+{
+ if (fwd)
+ return get_next_hop (c);
+ return get_prev_hop (c);
+}
+
+
+/**
+ * Is traffic coming from this sender 'FWD' traffic?
+ *
+ * @param c Connection to check.
+ * @param sender Peer identity of neighbor.
+ *
+ * @return #GNUNET_YES in case the sender is the 'prev' hop and therefore
+ * the traffic is 'FWD'.
+ * #GNUNET_NO for BCK.
+ * #GNUNET_SYSERR for errors.
+ */
+static int
+is_fwd (const struct CadetConnection *c,
+ const struct GNUNET_PeerIdentity *sender)
+{
+ GNUNET_PEER_Id id;
+
+ id = GNUNET_PEER_search (sender);
+ if (GMP_get_short_id (get_prev_hop (c)) == id)
+ return GNUNET_YES;
+
+ if (GMP_get_short_id (get_next_hop (c)) == id)
+ return GNUNET_NO;
+
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Sends a CONNECTION ACK message in reponse to a received CONNECTION_CREATE
+ * or a first CONNECTION_ACK directed to us.
+ *
+ * @param connection Connection to confirm.
+ * @param fwd Should we send it FWD? (root->dest)
+ * (First (~SYNACK) goes BCK, second (~ACK) goes FWD)
+ */
+static void
+send_connection_ack (struct CadetConnection *connection, int fwd)
+{
+ struct CadetTunnel3 *t;
+
+ t = connection->t;
+ LOG (GNUNET_ERROR_TYPE_INFO, "===> {%14s ACK} on connection %s\n",
+ GM_f2s (!fwd), GMC_2s (connection));
+ GMP_queue_add (get_hop (connection, fwd), NULL,
+ GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK,
+ GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK, 0,
+ sizeof (struct GNUNET_CADET_ConnectionACK),
+ connection, fwd, &conn_message_sent, NULL);
+ connection->pending_messages++;
+ if (CADET_TUNNEL3_NEW == GMT_get_cstate (t))
+ GMT_change_cstate (t, CADET_TUNNEL3_WAITING);
+ if (CADET_CONNECTION_READY != connection->state)
+ connection_change_state (connection, CADET_CONNECTION_SENT);
+}
+
+
+/**
+ * Send a notification that a connection is broken.
+ *
+ * @param c Connection that is broken.
+ * @param id1 Peer that has disconnected.
+ * @param id2 Peer that has disconnected.
+ * @param fwd Direction towards which to send it.
+ */
+static void
+send_broken (struct CadetConnection *c,
+ const struct GNUNET_PeerIdentity *id1,
+ const struct GNUNET_PeerIdentity *id2,
+ int fwd)
+{
+ struct GNUNET_CADET_ConnectionBroken msg;
+
+ msg.header.size = htons (sizeof (struct GNUNET_CADET_ConnectionBroken));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
+ msg.cid = c->id;
+ msg.peer1 = *id1;
+ msg.peer2 = *id2;
+ GMC_send_prebuilt_message (&msg.header,
+ GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN, 0,
+ c, fwd, GNUNET_YES, NULL, NULL);
+}
+
+
+/**
+ * Send a notification that a connection is broken, when a connection
+ * isn't even known to the local peer.
+ *
+ * @param connection_id Connection ID.
+ * @param id1 Peer that has disconnected, probably local peer.
+ * @param id2 Peer that has disconnected can be NULL if unknown.
+ * @param peer Peer to notify (neighbor who sent the connection).
+ */
+static void
+send_broken_unknown (const struct GNUNET_CADET_Hash *connection_id,
+ const struct GNUNET_PeerIdentity *id1,
+ const struct GNUNET_PeerIdentity *id2,
+ const struct GNUNET_PeerIdentity *peer_id)
+{
+ struct GNUNET_CADET_ConnectionBroken *msg;
+ struct CadetPeer *neighbor;
+
+ LOG (GNUNET_ERROR_TYPE_INFO, "===> BROKEN on unknown connection %s\n",
+ GNUNET_h2s (GM_h2hc (connection_id)));
+
+ msg = GNUNET_new (struct GNUNET_CADET_ConnectionBroken);
+ msg->header.size = htons (sizeof (struct GNUNET_CADET_ConnectionBroken));
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
+ msg->cid = *connection_id;
+ msg->peer1 = *id1;
+ if (NULL != id2)
+ msg->peer2 = *id2;
+ else
+ memset (&msg->peer2, 0, sizeof (msg->peer2));
+ neighbor = GMP_get (peer_id);
+ GMP_queue_add (neighbor, msg,
+ GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN,
+ GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN, 2,
+ sizeof (struct GNUNET_CADET_ConnectionBroken),
+ NULL, GNUNET_SYSERR, /* connection, fwd */
+ NULL, NULL); /* continuation */
+}
+
+
+/**
+ * Send keepalive packets for a connection.
+ *
+ * @param c Connection to keep alive..
+ * @param fwd Is this a FWD keepalive? (owner -> dest).
+ */
+static void
+send_connection_keepalive (struct CadetConnection *c, int fwd)
+{
+ struct GNUNET_MessageHeader msg;
+ struct CadetFlowControl *fc;
+
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "keepalive %s for connection %s\n",
+ GM_f2s (fwd), GMC_2s (c));
+
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ if (0 < fc->queue_n)
+ {
+ LOG (GNUNET_ERROR_TYPE_INFO, "not sending keepalive, traffic in queue\n");
+ }
+
+ GNUNET_STATISTICS_update (stats, "# keepalives sent", 1, GNUNET_NO);
+
+ GNUNET_assert (NULL != c->t);
+ msg.size = htons (sizeof (msg));
+ msg.type = htons (GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE);
+
+ GNUNET_assert (NULL ==
+ GMT_send_prebuilt_message (&msg, c->t, c,
+ GNUNET_NO, NULL, NULL));
+}
+
+
+/**
+ * Send CONNECTION_{CREATE/ACK} packets for a connection.
+ *
+ * @param c Connection for which to send the message.
+ * @param fwd If #GNUNET_YES, send CREATE, otherwise send ACK.
+ */
+static void
+connection_recreate (struct CadetConnection *c, int fwd)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "sending connection recreate\n");
+ if (fwd)
+ GMC_send_create (c);
+ else
+ send_connection_ack (c, GNUNET_NO);
+}
+
+
+/**
+ * Generic connection timer management.
+ * Depending on the role of the peer in the connection will send the
+ * appropriate message (build or keepalive)
+ *
+ * @param c Conncetion to maintain.
+ * @param fwd Is FWD?
+ */
+static void
+connection_maintain (struct CadetConnection *c, int fwd)
+{
+ if (GNUNET_NO != c->destroy)
+ return;
+
+ if (CADET_TUNNEL3_SEARCHING == GMT_get_cstate (c->t))
+ {
+ /* TODO DHT GET with RO_BART */
+ return;
+ }
+ switch (c->state)
+ {
+ case CADET_CONNECTION_NEW:
+ GNUNET_break (0);
+ /* fall-through */
+ case CADET_CONNECTION_SENT:
+ connection_recreate (c, fwd);
+ break;
+ case CADET_CONNECTION_READY:
+ send_connection_keepalive (c, fwd);
+ break;
+ default:
+ break;
+ }
+}
+
+
+
+/**
+ * Keep the connection alive.
+ *
+ * @param c Connection to keep alive.
+ * @param fwd Direction.
+ * @param shutdown Are we shutting down? (Don't send traffic)
+ * Non-zero value for true, not necessarily GNUNET_YES.
+ */
+static void
+connection_keepalive (struct CadetConnection *c, int fwd, int shutdown)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "%s keepalive for %s\n",
+ GM_f2s (fwd), GMC_2s (c));
+
+ if (fwd)
+ c->fwd_maintenance_task = GNUNET_SCHEDULER_NO_TASK;
+ else
+ c->bck_maintenance_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (GNUNET_NO != shutdown)
+ return;
+
+ connection_maintain (c, fwd);
+
+ /* Next execution will be scheduled by message_sent */
+}
+
+
+/**
+ * Keep the connection alive in the FWD direction.
+ *
+ * @param cls Closure (connection to keepalive).
+ * @param tc TaskContext.
+ */
+static void
+connection_fwd_keepalive (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ connection_keepalive ((struct CadetConnection *) cls,
+ GNUNET_YES,
+ tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN);
+}
+
+
+/**
+ * Keep the connection alive in the BCK direction.
+ *
+ * @param cls Closure (connection to keepalive).
+ * @param tc TaskContext.
+ */
+static void
+connection_bck_keepalive (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ connection_keepalive ((struct CadetConnection *) cls,
+ GNUNET_NO,
+ tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN);
+}
+
+
+/**
+ * Schedule next keepalive task, taking in consideration
+ * the connection state and number of retries.
+ *
+ * If the peer is not the origin, do nothing.
+ *
+ * @param c Connection for which to schedule the next keepalive.
+ * @param fwd Direction for the next keepalive.
+ */
+static void
+schedule_next_keepalive (struct CadetConnection *c, int fwd)
+{
+ struct GNUNET_TIME_Relative delay;
+ GNUNET_SCHEDULER_TaskIdentifier *task_id;
+ GNUNET_SCHEDULER_Task keepalive_task;
+
+ if (GNUNET_NO == GMC_is_origin (c, fwd))
+ return;
+
+ /* Calculate delay to use, depending on the state of the connection */
+ if (CADET_CONNECTION_READY == c->state)
+ {
+ delay = refresh_connection_time;
+ }
+ else
+ {
+ if (1 > c->create_retry)
+ c->create_retry = 1;
+ delay = GNUNET_TIME_relative_multiply (create_connection_time,
+ c->create_retry);
+ if (c->create_retry < 64)
+ c->create_retry *= 2;
+ }
+
+ /* Select direction-dependent parameters */
+ if (GNUNET_YES == fwd)
+ {
+ task_id = &c->fwd_maintenance_task;
+ keepalive_task = &connection_fwd_keepalive;
+ }
+ else
+ {
+ task_id = &c->bck_maintenance_task;
+ keepalive_task = &connection_bck_keepalive;
+ }
+
+ /* Check that no one scheduled it before us */
+ if (GNUNET_SCHEDULER_NO_TASK != *task_id)
+ {
+ /* No need for a _break. It can happen for instance when sending a SYNACK
+ * for a duplicate SYN: the first SYNACK scheduled the task. */
+ GNUNET_SCHEDULER_cancel (*task_id);
+ }
+
+ /* Schedule the task */
+ *task_id = GNUNET_SCHEDULER_add_delayed (delay, keepalive_task, c);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "next keepalive in %s\n",
+ GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
+}
+
+
+/**
+ * @brief Re-initiate traffic on this connection if necessary.
+ *
+ * Check if there is traffic queued towards this peer
+ * and the core transmit handle is NULL (traffic was stalled).
+ * If so, call core tmt rdy.
+ *
+ * @param c Connection on which initiate traffic.
+ * @param fwd Is this about fwd traffic?
+ */
+static void
+connection_unlock_queue (struct CadetConnection *c, int fwd)
+{
+ struct CadetPeer *peer;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "connection_unlock_queue %s on %s\n",
+ GM_f2s (fwd), GMC_2s (c));
+
+ if (GMC_is_terminal (c, fwd))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " is terminal!\n");
+ return;
+ }
+
+ peer = get_hop (c, fwd);
+ GMP_queue_unlock (peer, c);
+}
+
+
+/**
+ * Cancel all transmissions that belong to a certain connection.
+ *
+ * If the connection is scheduled for destruction and no more messages are
left,
+ * the connection will be destroyed by the continuation call.
+ *
+ * @param c Connection which to cancel. Might be destroyed during this call.
+ * @param fwd Cancel fwd traffic?
+ */
+static void
+connection_cancel_queues (struct CadetConnection *c, int fwd)
+{
+ struct CadetFlowControl *fc;
+ struct CadetPeer *peer;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " *** Cancel %s queues for connection %s\n",
+ GM_f2s (fwd), GMC_2s (c));
+ if (NULL == c)
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task)
+ {
+ GNUNET_SCHEDULER_cancel (fc->poll_task);
+ fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** Cancel POLL in ccq for fc %p\n", fc);
+ }
+ peer = get_hop (c, fwd);
+ GMP_queue_cancel (peer, c);
+}
+
+
+/**
+ * Function called if a connection has been stalled for a while,
+ * possibly due to a missed ACK. Poll the neighbor about its ACK status.
+ *
+ * @param cls Closure (poll ctx).
+ * @param tc TaskContext.
+ */
+static void
+connection_poll (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Callback called when a queued POLL message is sent.
+ *
+ * @param cls Closure (FC).
+ * @param c Connection this message was on.
+ * @param q Queue handler this call invalidates.
+ * @param type Type of message sent.
+ * @param fwd Was this a FWD going message?
+ * @param size Size of the message.
+ */
+static void
+poll_sent (void *cls,
+ struct CadetConnection *c,
+ struct CadetConnectionQueue *q,
+ uint16_t type, int fwd, size_t size)
+{
+ struct CadetFlowControl *fc = cls;
+
+ if (2 == c->destroy)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL canceled on shutdown\n");
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " *** POLL sent for , scheduling new one!\n");
+ fc->poll_msg = NULL;
+ fc->poll_time = GNUNET_TIME_STD_BACKOFF (fc->poll_time);
+ fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time,
+ &connection_poll, fc);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " task %u\n", fc->poll_task);
+
+}
+
+/**
+ * Function called if a connection has been stalled for a while,
+ * possibly due to a missed ACK. Poll the neighbor about its ACK status.
+ *
+ * @param cls Closure (poll ctx).
+ * @param tc TaskContext.
+ */
+static void
+connection_poll (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct CadetFlowControl *fc = cls;
+ struct GNUNET_CADET_Poll msg;
+ struct CadetConnection *c;
+
+ fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ {
+ return;
+ }
+
+ c = fc->c;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** Polling connection %s %s\n",
+ GMC_2s (c), fc == &c->fwd_fc ? "FWD" : "BCK");
+
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_POLL);
+ msg.header.size = htons (sizeof (msg));
+ msg.pid = htonl (fc->last_pid_sent);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** last pid sent: %u!\n",
fc->last_pid_sent);
+ fc->poll_msg =
+ GMC_send_prebuilt_message (&msg.header,
+ GNUNET_MESSAGE_TYPE_CADET_POLL,
+ fc->last_pid_sent,
+ c, fc == &c->fwd_fc, GNUNET_YES,
+ &poll_sent, fc);
+}
+
+
+/**
+ * Timeout function due to lack of keepalive/traffic from the owner.
+ * Destroys connection if called.
+ *
+ * @param cls Closure (connection to destroy).
+ * @param tc TaskContext.
+ */
+static void
+connection_fwd_timeout (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct CadetConnection *c = cls;
+
+ c->fwd_maintenance_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s FWD timed out. Destroying.\n",
+ GMC_2s (c));
+ if (GMC_is_origin (c, GNUNET_YES)) /* If local, leave. */
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ GMC_destroy (c);
+}
+
+
+/**
+ * Timeout function due to lack of keepalive/traffic from the destination.
+ * Destroys connection if called.
+ *
+ * @param cls Closure (connection to destroy).
+ * @param tc TaskContext
+ */
+static void
+connection_bck_timeout (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct CadetConnection *c = cls;
+
+ c->bck_maintenance_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s BCK timed out. Destroying.\n",
+ GMC_2s (c));
+
+ if (GMC_is_origin (c, GNUNET_NO)) /* If local, leave. */
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ GMC_destroy (c);
+}
+
+
+/**
+ * Resets the connection timeout task, some other message has done the
+ * task's job.
+ * - For the first peer on the direction this means to send
+ * a keepalive or a path confirmation message (either create or ACK).
+ * - For all other peers, this means to destroy the connection,
+ * due to lack of activity.
+ * Starts the timeout if no timeout was running (connection just created).
+ *
+ * @param c Connection whose timeout to reset.
+ * @param fwd Is this forward?
+ *
+ * TODO use heap to improve efficiency of scheduler.
+ */
+static void
+connection_reset_timeout (struct CadetConnection *c, int fwd)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s reset timeout\n", GM_f2s (fwd));
+
+ if (GMC_is_origin (c, fwd)) /* Startpoint */
+ {
+ schedule_next_keepalive (c, fwd);
+ }
+ else /* Relay, endpoint. */
+ {
+ struct GNUNET_TIME_Relative delay;
+ GNUNET_SCHEDULER_TaskIdentifier *ti;
+ GNUNET_SCHEDULER_Task f;
+
+ ti = fwd ? &c->fwd_maintenance_task : &c->bck_maintenance_task;
+
+ if (GNUNET_SCHEDULER_NO_TASK != *ti)
+ GNUNET_SCHEDULER_cancel (*ti);
+ delay = GNUNET_TIME_relative_multiply (refresh_connection_time, 4);
+ f = fwd ? &connection_fwd_timeout : &connection_bck_timeout;
+ *ti = GNUNET_SCHEDULER_add_delayed (delay, f, c);
+ }
+}
+
+
+/**
+ * Add the connection to the list of both neighbors.
+ *
+ * @param c Connection.
+ *
+ * @return #GNUNET_OK if everything went fine
+ * #GNUNET_SYSERR if the was an error and @c c is malformed.
+ */
+static int
+register_neighbors (struct CadetConnection *c)
+{
+ struct CadetPeer *next_peer;
+ struct CadetPeer *prev_peer;
+
+ next_peer = get_next_hop (c);
+ prev_peer = get_prev_hop (c);
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "register neighbors for connection %s\n",
+ GMC_2s (c));
+ path_debug (c->path);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "own pos %u\n", c->own_pos);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "putting connection %s to next peer %p\n",
+ GMC_2s (c), next_peer);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "next peer %p %s\n", next_peer, GMP_2s
(next_peer));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "putting connection %s to prev peer %p\n",
+ GMC_2s (c), prev_peer);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "prev peer %p %s\n", prev_peer, GMP_2s
(prev_peer));
+
+ if (GNUNET_NO == GMP_is_neighbor (next_peer)
+ || GNUNET_NO == GMP_is_neighbor (prev_peer))
+ {
+ if (GMC_is_origin (c, GNUNET_YES))
+ GNUNET_STATISTICS_update (stats, "# local bad paths", 1, GNUNET_NO);
+ GNUNET_STATISTICS_update (stats, "# bad paths", 1, GNUNET_NO);
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " register neighbors failed\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " prev: %s, neighbor?: %d\n",
+ GMP_2s (prev_peer), GMP_is_neighbor (prev_peer));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " next: %s, neighbor?: %d\n",
+ GMP_2s (next_peer), GMP_is_neighbor (next_peer));
+ return GNUNET_SYSERR;
+ }
+
+ GMP_add_connection (next_peer, c);
+ GMP_add_connection (prev_peer, c);
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Remove the connection from the list of both neighbors.
+ *
+ * @param c Connection.
+ */
+static void
+unregister_neighbors (struct CadetConnection *c)
+{
+ struct CadetPeer *peer;
+
+ peer = get_next_hop (c);
+ if (GNUNET_OK != GMP_remove_connection (peer, c))
+ {
+ GNUNET_assert (CADET_CONNECTION_NEW == c->state
+ || CADET_CONNECTION_DESTROYED == c->state);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate: %u\n", c->state);
+ if (NULL != c->t) GMT_debug (c->t);
+ }
+
+ peer = get_prev_hop (c);
+ if (GNUNET_OK != GMP_remove_connection (peer, c))
+ {
+ GNUNET_assert (CADET_CONNECTION_NEW == c->state
+ || CADET_CONNECTION_DESTROYED == c->state);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate: %u\n", c->state);
+ if (NULL != c->t) GMT_debug (c->t);
+ }
+}
+
+
+/**
+ * Bind the connection to the peer and the tunnel to that peer.
+ *
+ * If the peer has no tunnel, create one. Update tunnel and connection
+ * data structres to reflect new status.
+ *
+ * @param c Connection.
+ * @param peer Peer.
+ */
+static void
+add_to_peer (struct CadetConnection *c, struct CadetPeer *peer)
+{
+ GMP_add_tunnel (peer);
+ c->t = GMP_get_tunnel (peer);
+ GMT_add_connection (c->t, c);
+}
+
+
+/**
+ * Builds a path from a PeerIdentity array.
+ *
+ * @param peers PeerIdentity array.
+ * @param size Size of the @c peers array.
+ * @param own_pos Output parameter: own position in the path.
+ *
+ * @return Fixed and shortened path.
+ */
+static struct CadetPeerPath *
+build_path_from_peer_ids (struct GNUNET_PeerIdentity *peers,
+ unsigned int size,
+ unsigned int *own_pos)
+{
+ struct CadetPeerPath *path;
+ GNUNET_PEER_Id shortid;
+ unsigned int i;
+ unsigned int j;
+ unsigned int offset;
+
+ /* Create path */
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Creating path...\n");
+ path = path_new (size);
+ *own_pos = 0;
+ offset = 0;
+ for (i = 0; i < size; i++)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " - %u: taking %s\n",
+ i, GNUNET_i2s (&peers[i]));
+ shortid = GNUNET_PEER_intern (&peers[i]);
+
+ /* Check for loops / duplicates */
+ for (j = 0; j < i - offset; j++)
+ {
+ if (path->peers[j] == shortid)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " already exists at pos %u\n", j);
+ offset = i - j;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " offset now %u\n", offset);
+ GNUNET_PEER_change_rc (shortid, -1);
+ }
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " storing at %u\n", i - offset);
+ path->peers[i - offset] = shortid;
+ if (path->peers[i - offset] == myid)
+ *own_pos = i - offset;
+ }
+ path->length -= offset;
+
+ if (path->peers[*own_pos] != myid)
+ {
+ /* create path: self not found in path through self */
+ GNUNET_break_op (0);
+ path_destroy (path);
+ return NULL;
+ }
+
+ return path;
+}
+
+
+/**
+ * Log receipt of message on stderr (INFO level).
+ *
+ * @param message Message received.
+ * @param peer Peer who sent the message.
+ * @param hash Connection ID.
+ */
+static void
+log_message (const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_CADET_Hash *hash)
+{
+ LOG (GNUNET_ERROR_TYPE_INFO, "<-- %s on connection %s from %s\n",
+ GM_m2s (ntohs (message->type)), GNUNET_h2s (GM_h2hc (hash)),
+ GNUNET_i2s (peer));
+}
+
+/******************************************************************************/
+/******************************** API
***********************************/
+/******************************************************************************/
+
+/**
+ * Core handler for connection creation.
+ *
+ * @param cls Closure (unused).
+ * @param peer Sender (neighbor).
+ * @param message Message.
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+int
+GMC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_CADET_ConnectionCreate *msg;
+ struct GNUNET_PeerIdentity *id;
+ struct GNUNET_CADET_Hash *cid;
+ struct CadetPeerPath *path;
+ struct CadetPeer *dest_peer;
+ struct CadetPeer *orig_peer;
+ struct CadetConnection *c;
+ unsigned int own_pos;
+ uint16_t size;
+
+ /* Check size */
+ size = ntohs (message->size);
+ if (size < sizeof (struct GNUNET_CADET_ConnectionCreate))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
+
+ /* Calculate hops */
+ size -= sizeof (struct GNUNET_CADET_ConnectionCreate);
+ if (size % sizeof (struct GNUNET_PeerIdentity))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
+ size /= sizeof (struct GNUNET_PeerIdentity);
+ if (1 > size)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " path has %u hops.\n", size);
+
+ /* Get parameters */
+ msg = (struct GNUNET_CADET_ConnectionCreate *) message;
+ cid = &msg->cid;
+ log_message (message, peer, cid);
+ id = (struct GNUNET_PeerIdentity *) &msg[1];
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " origin: %s\n", GNUNET_i2s (id));
+
+ /* Create connection */
+ c = connection_get (cid);
+ if (NULL == c)
+ {
+ path = build_path_from_peer_ids ((struct GNUNET_PeerIdentity *) &msg[1],
+ size, &own_pos);
+ if (NULL == path)
+ return GNUNET_OK;
+ if (0 == own_pos)
+ {
+ GNUNET_break_op (0);
+ path_destroy (path);
+ return GNUNET_OK;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Own position: %u\n", own_pos);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Creating connection\n");
+ c = GMC_new (cid, NULL, path_duplicate (path), own_pos);
+ if (NULL == c)
+ {
+ if (path->length - 1 == own_pos)
+ {
+ /* If we are destination, why did the creation fail? */
+ GNUNET_break (0);
+ return GNUNET_OK;
+ }
+ send_broken_unknown (cid, &my_full_id,
+ GNUNET_PEER_resolve2 (path->peers[own_pos + 1]),
+ peer);
+ path_destroy (path);
+ return GNUNET_OK;
+ }
+ GMP_add_path_to_all (path, GNUNET_NO);
+ connection_reset_timeout (c, GNUNET_YES);
+ }
+ else
+ {
+ path = path_duplicate (c->path);
+ }
+ if (CADET_CONNECTION_NEW == c->state)
+ connection_change_state (c, CADET_CONNECTION_SENT);
+
+ /* Remember peers */
+ dest_peer = GMP_get (&id[size - 1]);
+ orig_peer = GMP_get (&id[0]);
+
+ /* Is it a connection to us? */
+ if (c->own_pos == path->length - 1)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " It's for us!\n");
+ GMP_add_path_to_origin (orig_peer, path_duplicate (path), GNUNET_YES);
+
+ add_to_peer (c, orig_peer);
+ if (CADET_TUNNEL3_NEW == GMT_get_cstate (c->t))
+ GMT_change_cstate (c->t, CADET_TUNNEL3_WAITING);
+
+ send_connection_ack (c, GNUNET_NO);
+ if (CADET_CONNECTION_SENT == c->state)
+ connection_change_state (c, CADET_CONNECTION_ACK);
+ }
+ else
+ {
+ /* It's for somebody else! Retransmit. */
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Retransmitting.\n");
+ GMP_add_path (dest_peer, path_duplicate (path), GNUNET_NO);
+ GMP_add_path_to_origin (orig_peer, path_duplicate (path), GNUNET_NO);
+ GMC_send_prebuilt_message (message,
+ GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, 0,
+ c, GNUNET_YES, GNUNET_YES,
+ NULL, NULL);
+ }
+ path_destroy (path);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Core handler for path confirmations.
+ *
+ * @param cls closure
+ * @param message message
+ * @param peer peer identity this notification is about
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+int
+GMC_handle_confirm (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_CADET_ConnectionACK *msg;
+ struct CadetConnection *c;
+ struct CadetPeerPath *p;
+ struct CadetPeer *pi;
+ enum CadetConnectionState oldstate;
+ int fwd;
+
+ msg = (struct GNUNET_CADET_ConnectionACK *) message;
+ log_message (message, peer, &msg->cid);
+ c = connection_get (&msg->cid);
+ if (NULL == c)
+ {
+ GNUNET_STATISTICS_update (stats, "# control on unknown connection",
+ 1, GNUNET_NO);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " don't know the connection!\n");
+ send_broken_unknown (&msg->cid, &my_full_id, NULL, peer);
+ return GNUNET_OK;
+ }
+
+ if (GNUNET_NO != c->destroy)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " connection being destroyed\n");
+ return GNUNET_OK;
+ }
+
+ oldstate = c->state;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " via peer %s\n", GNUNET_i2s (peer));
+ pi = GMP_get (peer);
+ if (get_next_hop (c) == pi)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " SYNACK\n");
+ fwd = GNUNET_NO;
+ if (CADET_CONNECTION_SENT == oldstate)
+ connection_change_state (c, CADET_CONNECTION_ACK);
+ }
+ else if (get_prev_hop (c) == pi)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ACK\n");
+ fwd = GNUNET_YES;
+ connection_change_state (c, CADET_CONNECTION_READY);
+ }
+ else
+ {
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
+
+ connection_reset_timeout (c, fwd);
+
+ /* Add path to peers? */
+ p = c->path;
+ if (NULL != p)
+ {
+ GMP_add_path_to_all (p, GNUNET_YES);
+ }
+ else
+ {
+ GNUNET_break (0);
+ }
+
+ /* Message for us as creator? */
+ if (GMC_is_origin (c, GNUNET_YES))
+ {
+ if (GNUNET_NO != fwd)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Connection (SYN)ACK for us!\n");
+
+ /* If just created, cancel the short timeout and start a long one */
+ if (CADET_CONNECTION_SENT == oldstate)
+ connection_reset_timeout (c, GNUNET_YES);
+
+ /* Change connection state */
+ connection_change_state (c, CADET_CONNECTION_READY);
+ send_connection_ack (c, GNUNET_YES);
+
+ /* Change tunnel state, trigger KX */
+ if (CADET_TUNNEL3_WAITING == GMT_get_cstate (c->t))
+ GMT_change_cstate (c->t, CADET_TUNNEL3_READY);
+
+ return GNUNET_OK;
+ }
+
+ /* Message for us as destination? */
+ if (GMC_is_terminal (c, GNUNET_YES))
+ {
+ if (GNUNET_YES != fwd)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Connection ACK for us!\n");
+
+ /* If just created, cancel the short timeout and start a long one */
+ if (CADET_CONNECTION_ACK == oldstate)
+ connection_reset_timeout (c, GNUNET_NO);
+
+ /* Change tunnel state */
+ if (CADET_TUNNEL3_WAITING == GMT_get_cstate (c->t))
+ GMT_change_cstate (c->t, CADET_TUNNEL3_READY);
+
+ return GNUNET_OK;
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n");
+ GMC_send_prebuilt_message (message,
+ GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK, 0,
+ c, fwd, GNUNET_YES, NULL, NULL);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Core handler for notifications of broken connections.
+ *
+ * @param cls Closure (unused).
+ * @param id Peer identity of sending neighbor.
+ * @param message Message.
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+int
+GMC_handle_broken (void* cls,
+ const struct GNUNET_PeerIdentity* id,
+ const struct GNUNET_MessageHeader* message)
+{
+ struct GNUNET_CADET_ConnectionBroken *msg;
+ struct CadetConnection *c;
+ int fwd;
+
+ msg = (struct GNUNET_CADET_ConnectionBroken *) message;
+ log_message (message, id, &msg->cid);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n",
+ GNUNET_i2s (&msg->peer1));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n",
+ GNUNET_i2s (&msg->peer2));
+ c = connection_get (&msg->cid);
+ if (NULL == c)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate CONNECTION_BROKEN\n");
+ return GNUNET_OK;
+ }
+
+ fwd = is_fwd (c, id);
+ if (GMC_is_terminal (c, fwd))
+ {
+ struct GNUNET_MessageHeader *out_msg;
+ struct CadetPeer *neighbor;
+ struct CadetPeer *endpoint;
+
+ neighbor = get_hop (c, !fwd);
+ endpoint = GMP_get_short (c->path->peers[c->path->length - 1]);
+ path_invalidate (c->path);
+ GMP_notify_broken_link (endpoint, &msg->peer1, &msg->peer2);
+ c->state = CADET_CONNECTION_DESTROYED;
+ while (NULL != (out_msg = GMP_connection_pop (neighbor, c)))
+ {
+ GNUNET_assert (NULL ==
+ GMT_send_prebuilt_message (out_msg, c->t, NULL,
GNUNET_YES,
+ NULL, NULL));
+ }
+
+ GMC_destroy (c);
+ }
+ else
+ {
+ GMC_send_prebuilt_message (message,
+ GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN, 0,
+ c, fwd, GNUNET_YES, NULL, NULL);
+ c->destroy = GNUNET_YES;
+ connection_cancel_queues (c, !fwd);
+ }
+
+ return GNUNET_OK;
+
+}
+
+
+/**
+ * Core handler for tunnel destruction
+ *
+ * @param cls Closure (unused).
+ * @param peer Peer identity of sending neighbor.
+ * @param message Message.
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+int
+GMC_handle_destroy (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_CADET_ConnectionDestroy *msg;
+ struct CadetConnection *c;
+ int fwd;
+
+ msg = (struct GNUNET_CADET_ConnectionDestroy *) message;
+ log_message (message, peer, &msg->cid);
+ c = connection_get (&msg->cid);
+ if (NULL == c)
+ {
+ /* Probably already got the message from another path,
+ * destroyed the tunnel and retransmitted to children.
+ * Safe to ignore.
+ */
+ GNUNET_STATISTICS_update (stats, "# control on unknown connection",
+ 1, GNUNET_NO);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " connection unknown: already
destroyed?\n");
+ return GNUNET_OK;
+ }
+ fwd = is_fwd (c, peer);
+ if (GNUNET_SYSERR == fwd)
+ {
+ GNUNET_break_op (0); /* FIXME */
+ return GNUNET_OK;
+ }
+ if (GNUNET_NO == GMC_is_terminal (c, fwd))
+ GMC_send_prebuilt_message (message,
+ GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY, 0,
+ c, fwd, GNUNET_YES, NULL, NULL);
+ else if (0 == c->pending_messages)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " directly destroying connection!\n");
+ GMC_destroy (c);
+ return GNUNET_OK;
+ }
+ c->destroy = GNUNET_YES;
+ c->state = CADET_CONNECTION_DESTROYED;
+ if (NULL != c->t)
+ {
+ GMT_remove_connection (c->t, c);
+ c->t = NULL;
+ }
+
+ return GNUNET_OK;
+}
+
+/**
+ * Generic handler for cadet network encrypted traffic.
+ *
+ * @param peer Peer identity this notification is about.
+ * @param msg Encrypted message.
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+static int
+handle_cadet_encrypted (const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_CADET_Encrypted *msg)
+{
+ struct CadetConnection *c;
+ struct CadetPeer *neighbor;
+ struct CadetFlowControl *fc;
+ GNUNET_PEER_Id peer_id;
+ uint32_t pid;
+ uint32_t ttl;
+ size_t size;
+ int fwd;
+
+ log_message (&msg->header, peer, &msg->cid);
+
+ /* Check size */
+ size = ntohs (msg->header.size);
+ if (size <
+ sizeof (struct GNUNET_CADET_Encrypted) +
+ sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
+
+ /* Check connection */
+ c = connection_get (&msg->cid);
+ if (NULL == c)
+ {
+ GNUNET_STATISTICS_update (stats, "# unknown connection", 1, GNUNET_NO);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "enc on unknown connection %s\n",
+ GNUNET_h2s (GM_h2hc (&msg->cid)));
+ send_broken_unknown (&msg->cid, &my_full_id, NULL, peer);
+ return GNUNET_OK;
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " connection %s\n", GMC_2s (c));
+
+ /* Check if origin is as expected */
+ neighbor = get_prev_hop (c);
+ peer_id = GNUNET_PEER_search (peer);
+ if (peer_id == GMP_get_short_id (neighbor))
+ {
+ fwd = GNUNET_YES;
+ }
+ else
+ {
+ neighbor = get_next_hop (c);
+ if (peer_id == GMP_get_short_id (neighbor))
+ {
+ fwd = GNUNET_NO;
+ }
+ else
+ {
+ /* Unexpected peer sending traffic on a connection. */
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
+ }
+
+ /* Check PID */
+ fc = fwd ? &c->bck_fc : &c->fwd_fc;
+ pid = ntohl (msg->pid);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " PID %u (expected %u+)\n",
+ pid, fc->last_pid_recv + 1);
+ if (GM_is_pid_bigger (pid, fc->last_ack_sent))
+ {
+ GNUNET_STATISTICS_update (stats, "# unsolicited message", 1, GNUNET_NO);
+ GNUNET_break_op (0);
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Received PID %u, (prev %u), ACK %u\n",
+ pid, fc->last_pid_recv, fc->last_ack_sent);
+ return GNUNET_OK;
+ }
+ if (GNUNET_NO == GM_is_pid_bigger (pid, fc->last_pid_recv))
+ {
+ GNUNET_STATISTICS_update (stats, "# duplicate PID", 1, GNUNET_NO);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " PID %u not expected (%u+), dropping!\n",
+ pid, fc->last_pid_recv + 1);
+ return GNUNET_OK;
+ }
+ if (CADET_CONNECTION_SENT == c->state || CADET_CONNECTION_ACK == c->state)
+ connection_change_state (c, CADET_CONNECTION_READY);
+ connection_reset_timeout (c, fwd);
+ fc->last_pid_recv = pid;
+
+ /* Is this message for us? */
+ if (GMC_is_terminal (c, fwd))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " message for us!\n");
+ GNUNET_STATISTICS_update (stats, "# messages received", 1, GNUNET_NO);
+
+ if (NULL == c->t)
+ {
+ GNUNET_break (GNUNET_NO != c->destroy);
+ return GNUNET_OK;
+ }
+ fc->last_pid_recv = pid;
+ GMT_handle_encrypted (c->t, msg);
+ GMC_send_ack (c, fwd, GNUNET_NO);
+ return GNUNET_OK;
+ }
+
+ /* Message not for us: forward to next hop */
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n");
+ ttl = ntohl (msg->ttl);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ttl: %u\n", ttl);
+ if (ttl == 0)
+ {
+ GNUNET_STATISTICS_update (stats, "# TTL drops", 1, GNUNET_NO);
+ LOG (GNUNET_ERROR_TYPE_WARNING, " TTL is 0, DROPPING!\n");
+ GMC_send_ack (c, fwd, GNUNET_NO);
+ return GNUNET_OK;
+ }
+
+ GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO);
+ GMC_send_prebuilt_message (&msg->header,
+ GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED, 0,
+ c, fwd, GNUNET_NO, NULL, NULL);
+
+ return GNUNET_OK;
+}
+
+/**
+ * Generic handler for cadet network encrypted traffic.
+ *
+ * @param peer Peer identity this notification is about.
+ * @param msg Encrypted message.
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+static int
+handle_cadet_kx (const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_CADET_KX *msg)
+{
+ struct CadetConnection *c;
+ struct CadetPeer *neighbor;
+ GNUNET_PEER_Id peer_id;
+ size_t size;
+ int fwd;
+
+ log_message (&msg->header, peer, &msg->cid);
+
+ /* Check size */
+ size = ntohs (msg->header.size);
+ if (size <
+ sizeof (struct GNUNET_CADET_KX) +
+ sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
+
+ /* Check connection */
+ c = connection_get (&msg->cid);
+ if (NULL == c)
+ {
+ GNUNET_STATISTICS_update (stats, "# unknown connection", 1, GNUNET_NO);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "kx on unknown connection %s\n",
+ GNUNET_h2s (GM_h2hc (&msg->cid)));
+ send_broken_unknown (&msg->cid, &my_full_id, NULL, peer);
+ return GNUNET_OK;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " on connection %s\n", GMC_2s (c));
+
+ /* Check if origin is as expected */
+ neighbor = get_prev_hop (c);
+ peer_id = GNUNET_PEER_search (peer);
+ if (peer_id == GMP_get_short_id (neighbor))
+ {
+ fwd = GNUNET_YES;
+ }
+ else
+ {
+ neighbor = get_next_hop (c);
+ if (peer_id == GMP_get_short_id (neighbor))
+ {
+ fwd = GNUNET_NO;
+ }
+ else
+ {
+ /* Unexpected peer sending traffic on a connection. */
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
+ }
+
+ /* Count as connection confirmation. */
+ if (CADET_CONNECTION_SENT == c->state || CADET_CONNECTION_ACK == c->state)
+ {
+ connection_change_state (c, CADET_CONNECTION_READY);
+ if (NULL != c->t)
+ {
+ if (CADET_TUNNEL3_WAITING == GMT_get_cstate (c->t))
+ GMT_change_cstate (c->t, CADET_TUNNEL3_READY);
+ }
+ }
+ connection_reset_timeout (c, fwd);
+
+ /* Is this message for us? */
+ if (GMC_is_terminal (c, fwd))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " message for us!\n");
+ GNUNET_STATISTICS_update (stats, "# messages received", 1, GNUNET_NO);
+ if (NULL == c->t)
+ {
+ GNUNET_break (0);
+ return GNUNET_OK;
+ }
+ GMT_handle_kx (c->t, &msg[1].header);
+ return GNUNET_OK;
+ }
+
+ /* Message not for us: forward to next hop */
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n");
+ GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO);
+ GMC_send_prebuilt_message (&msg->header, GNUNET_MESSAGE_TYPE_CADET_KX, 0,
+ c, fwd, GNUNET_NO, NULL, NULL);
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Core handler for encrypted cadet network traffic (channel mgmt, data).
+ *
+ * @param cls Closure (unused).
+ * @param message Message received.
+ * @param peer Peer who sent the message.
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+int
+GMC_handle_encrypted (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message)
+{
+ return handle_cadet_encrypted (peer,
+ (struct GNUNET_CADET_Encrypted *)message);
+}
+
+
+/**
+ * Core handler for key exchange traffic (ephemeral key, ping, pong).
+ *
+ * @param cls Closure (unused).
+ * @param message Message received.
+ * @param peer Peer who sent the message.
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+int
+GMC_handle_kx (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message)
+{
+ return handle_cadet_kx (peer,
+ (struct GNUNET_CADET_KX *) message);
+}
+
+
+/**
+ * Core handler for cadet network traffic point-to-point acks.
+ *
+ * @param cls closure
+ * @param message message
+ * @param peer peer identity this notification is about
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+int
+GMC_handle_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_CADET_ACK *msg;
+ struct CadetConnection *c;
+ struct CadetFlowControl *fc;
+ GNUNET_PEER_Id id;
+ uint32_t ack;
+ int fwd;
+
+ msg = (struct GNUNET_CADET_ACK *) message;
+ log_message (message, peer, &msg->cid);
+ c = connection_get (&msg->cid);
+ if (NULL == c)
+ {
+ GNUNET_STATISTICS_update (stats, "# ack on unknown connection", 1,
+ GNUNET_NO);
+ send_broken_unknown (&msg->cid, &my_full_id, NULL, peer);
+ return GNUNET_OK;
+ }
+
+ /* Is this a forward or backward ACK? */
+ id = GNUNET_PEER_search (peer);
+ if (GMP_get_short_id (get_next_hop (c)) == id)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD ACK\n");
+ fc = &c->fwd_fc;
+ fwd = GNUNET_YES;
+ }
+ else if (GMP_get_short_id (get_prev_hop (c)) == id)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK ACK\n");
+ fc = &c->bck_fc;
+ fwd = GNUNET_NO;
+ }
+ else
+ {
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
+
+ ack = ntohl (msg->ack);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ACK %u (was %u)\n",
+ ack, fc->last_ack_recv);
+ if (GM_is_pid_bigger (ack, fc->last_ack_recv))
+ fc->last_ack_recv = ack;
+
+ /* Cancel polling if the ACK is big enough. */
+ if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task &&
+ GM_is_pid_bigger (fc->last_ack_recv, fc->last_pid_sent))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Cancel poll\n");
+ GNUNET_SCHEDULER_cancel (fc->poll_task);
+ fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
+ fc->poll_time = GNUNET_TIME_UNIT_SECONDS;
+ }
+
+ connection_unlock_queue (c, fwd);
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Core handler for cadet network traffic point-to-point ack polls.
+ *
+ * @param cls closure
+ * @param message message
+ * @param peer peer identity this notification is about
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+int
+GMC_handle_poll (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_CADET_Poll *msg;
+ struct CadetConnection *c;
+ struct CadetFlowControl *fc;
+ GNUNET_PEER_Id id;
+ uint32_t pid;
+ int fwd;
+
+ msg = (struct GNUNET_CADET_Poll *) message;
+ log_message (message, peer, &msg->cid);
+ c = connection_get (&msg->cid);
+ if (NULL == c)
+ {
+ GNUNET_STATISTICS_update (stats, "# poll on unknown connection", 1,
+ GNUNET_NO);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL message on unknown connection %s!\n",
+ GNUNET_h2s (GM_h2hc (&msg->cid)));
+ send_broken_unknown (&msg->cid, &my_full_id, NULL, peer);
+ return GNUNET_OK;
+ }
+
+ /* Is this a forward or backward ACK?
+ * Note: a poll should never be needed in a loopback case,
+ * since there is no possiblility of packet loss there, so
+ * this way of discerining FWD/BCK should not be a problem.
+ */
+ id = GNUNET_PEER_search (peer);
+ if (GMP_get_short_id (get_next_hop (c)) == id)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD FC\n");
+ fc = &c->fwd_fc;
+ }
+ else if (GMP_get_short_id (get_prev_hop (c)) == id)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK FC\n");
+ fc = &c->bck_fc;
+ }
+ else
+ {
+ GNUNET_break_op (0);
+ return GNUNET_OK;
+ }
+
+ pid = ntohl (msg->pid);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " PID %u, OLD %u\n", pid, fc->last_pid_recv);
+ fc->last_pid_recv = pid;
+ fwd = fc == &c->bck_fc;
+ GMC_send_ack (c, fwd, GNUNET_YES);
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Send an ACK on the appropriate connection/channel, depending on
+ * the direction and the position of the peer.
+ *
+ * @param c Which connection to send the hop-by-hop ACK.
+ * @param fwd Is this a fwd ACK? (will go dest->root).
+ * @param force Send the ACK even if suboptimal (e.g. requested by POLL).
+ */
+void
+GMC_send_ack (struct CadetConnection *c, int fwd, int force)
+{
+ unsigned int buffer;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "GMC send %s ACK on %s\n",
+ GM_f2s (fwd), GMC_2s (c));
+
+ if (NULL == c)
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ if (GNUNET_NO != c->destroy)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " being destroyed, why bother...\n");
+ return;
+ }
+
+ /* Get available buffer space */
+ if (GMC_is_terminal (c, fwd))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " getting from all channels\n");
+ buffer = GMT_get_channels_buffer (c->t);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " getting from one connection\n");
+ buffer = GMC_get_buffer (c, fwd);
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer available: %u\n", buffer);
+ if (0 == buffer && GNUNET_NO == force)
+ return;
+
+ /* Send available buffer space */
+ if (GMC_is_origin (c, fwd))
+ {
+ GNUNET_assert (NULL != c->t);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channels...\n");
+ GMT_unchoke_channels (c->t);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on connection\n");
+ send_ack (c, buffer, fwd, force);
+ }
+}
+
+
+/**
+ * Initialize the connections subsystem
+ *
+ * @param c Configuration handle.
+ */
+void
+GMC_init (const struct GNUNET_CONFIGURATION_Handle *c)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_MSGS_QUEUE",
+ &max_msgs_queue))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "CADET", "MAX_MSGS_QUEUE", "MISSING");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_CONNECTIONS",
+ &max_connections))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "CADET", "MAX_CONNECTIONS", "MISSING");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (c, "CADET",
"REFRESH_CONNECTION_TIME",
+ &refresh_connection_time))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "CADET", "REFRESH_CONNECTION_TIME", "MISSING");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ create_connection_time = GNUNET_TIME_UNIT_SECONDS;
+ connections = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_NO);
+}
+
+
+/**
+ * Destroy each connection on shutdown.
+ *
+ * @param cls Closure (unused).
+ * @param key Current key code (CID, unused).
+ * @param value Value in the hash map (connection)
+ *
+ * @return #GNUNET_YES, because we should continue to iterate,
+ */
+static int
+shutdown_iterator (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ struct CadetConnection *c = value;
+
+ GMC_destroy (c);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Shut down the connections subsystem.
+ */
+void
+GMC_shutdown (void)
+{
+ GNUNET_CONTAINER_multihashmap_iterate (connections, &shutdown_iterator,
NULL);
+ GNUNET_CONTAINER_multihashmap_destroy (connections);
+ connections = NULL;
+}
+
+
+struct CadetConnection *
+GMC_new (const struct GNUNET_CADET_Hash *cid,
+ struct CadetTunnel3 *t,
+ struct CadetPeerPath *p,
+ unsigned int own_pos)
+{
+ struct CadetConnection *c;
+
+ c = GNUNET_new (struct CadetConnection);
+ c->id = *cid;
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_put (connections,
+ GMC_get_h (c), c,
+
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ fc_init (&c->fwd_fc);
+ fc_init (&c->bck_fc);
+ c->fwd_fc.c = c;
+ c->bck_fc.c = c;
+
+ c->t = t;
+ GNUNET_assert (own_pos <= p->length - 1);
+ c->own_pos = own_pos;
+ c->path = p;
+ p->c = c;
+
+ if (GNUNET_OK != register_neighbors (c))
+ {
+ if (0 == own_pos)
+ {
+ path_invalidate (c->path);
+ c->t = NULL;
+ c->path = NULL;
+ }
+ GMC_destroy (c);
+ return NULL;
+ }
+
+ return c;
+}
+
+
+void
+GMC_destroy (struct CadetConnection *c)
+{
+ if (NULL == c)
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ if (2 == c->destroy) /* cancel queues -> GMP_queue_cancel -> q_destroy -> */
+ return; /* -> message_sent -> GMC_destroy. Don't loop. */
+ c->destroy = 2;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying connection %s\n", GMC_2s (c));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " fc's f: %p, b: %p\n",
+ &c->fwd_fc, &c->bck_fc);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " fc tasks f: %u, b: %u\n",
+ c->fwd_fc.poll_task, c->bck_fc.poll_task);
+
+ /* Cancel all traffic */
+ if (NULL != c->path)
+ {
+ connection_cancel_queues (c, GNUNET_YES);
+ connection_cancel_queues (c, GNUNET_NO);
+ unregister_neighbors (c);
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " fc tasks f: %u, b: %u\n",
+ c->fwd_fc.poll_task, c->bck_fc.poll_task);
+
+ /* Cancel maintainance task (keepalive/timeout) */
+ if (NULL != c->fwd_fc.poll_msg)
+ {
+ GMC_cancel (c->fwd_fc.poll_msg);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL msg FWD canceled\n");
+ }
+ if (NULL != c->bck_fc.poll_msg)
+ {
+ GMC_cancel (c->bck_fc.poll_msg);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL msg BCK canceled\n");
+ }
+
+ /* Delete from tunnel */
+ if (NULL != c->t)
+ GMT_remove_connection (c->t, c);
+
+ if (GNUNET_NO == GMC_is_origin (c, GNUNET_YES) && NULL != c->path)
+ path_destroy (c->path);
+ if (GNUNET_SCHEDULER_NO_TASK != c->fwd_maintenance_task)
+ GNUNET_SCHEDULER_cancel (c->fwd_maintenance_task);
+ if (GNUNET_SCHEDULER_NO_TASK != c->bck_maintenance_task)
+ GNUNET_SCHEDULER_cancel (c->bck_maintenance_task);
+ if (GNUNET_SCHEDULER_NO_TASK != c->fwd_fc.poll_task)
+ {
+ GNUNET_SCHEDULER_cancel (c->fwd_fc.poll_task);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL FWD canceled\n");
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != c->bck_fc.poll_task)
+ {
+ GNUNET_SCHEDULER_cancel (c->bck_fc.poll_task);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL BCK canceled\n");
+ }
+
+ GNUNET_break (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (connections,
+ GMC_get_h (c), c));
+
+ GNUNET_STATISTICS_update (stats, "# connections", -1, GNUNET_NO);
+ GNUNET_free (c);
+}
+
+/**
+ * Get the connection ID.
+ *
+ * @param c Connection to get the ID from.
+ *
+ * @return ID of the connection.
+ */
+const struct GNUNET_CADET_Hash *
+GMC_get_id (const struct CadetConnection *c)
+{
+ return &c->id;
+}
+
+
+/**
+ * Get the connection ID.
+ *
+ * @param c Connection to get the ID from.
+ *
+ * @return ID of the connection.
+ */
+const struct GNUNET_HashCode *
+GMC_get_h (const struct CadetConnection *c)
+{
+ return GM_h2hc (&c->id);
+}
+
+
+/**
+ * Get the connection path.
+ *
+ * @param c Connection to get the path from.
+ *
+ * @return path used by the connection.
+ */
+const struct CadetPeerPath *
+GMC_get_path (const struct CadetConnection *c)
+{
+ if (GNUNET_NO == c->destroy)
+ return c->path;
+ return NULL;
+}
+
+
+/**
+ * Get the connection state.
+ *
+ * @param c Connection to get the state from.
+ *
+ * @return state of the connection.
+ */
+enum CadetConnectionState
+GMC_get_state (const struct CadetConnection *c)
+{
+ return c->state;
+}
+
+/**
+ * Get the connection tunnel.
+ *
+ * @param c Connection to get the tunnel from.
+ *
+ * @return tunnel of the connection.
+ */
+struct CadetTunnel3 *
+GMC_get_tunnel (const struct CadetConnection *c)
+{
+ return c->t;
+}
+
+
+/**
+ * Get free buffer space in a connection.
+ *
+ * @param c Connection.
+ * @param fwd Is query about FWD traffic?
+ *
+ * @return Free buffer space [0 - max_msgs_queue/max_connections]
+ */
+unsigned int
+GMC_get_buffer (struct CadetConnection *c, int fwd)
+{
+ struct CadetFlowControl *fc;
+
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+
+ return (fc->queue_max - fc->queue_n);
+}
+
+/**
+ * Get how many messages have we allowed to send to us from a direction.
+ *
+ * @param c Connection.
+ * @param fwd Are we asking about traffic from FWD (BCK messages)?
+ *
+ * @return last_ack_sent - last_pid_recv
+ */
+unsigned int
+GMC_get_allowed (struct CadetConnection *c, int fwd)
+{
+ struct CadetFlowControl *fc;
+
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ if (GM_is_pid_bigger(fc->last_pid_recv, fc->last_ack_sent))
+ {
+ return 0;
+ }
+ return (fc->last_ack_sent - fc->last_pid_recv);
+}
+
+/**
+ * Get messages queued in a connection.
+ *
+ * @param c Connection.
+ * @param fwd Is query about FWD traffic?
+ *
+ * @return Number of messages queued.
+ */
+unsigned int
+GMC_get_qn (struct CadetConnection *c, int fwd)
+{
+ struct CadetFlowControl *fc;
+
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+
+ return fc->queue_n;
+}
+
+
+/**
+ * Get next PID to use.
+ *
+ * @param c Connection.
+ * @param fwd Is query about FWD traffic?
+ *
+ * @return Last PID used + 1.
+ */
+unsigned int
+GMC_get_pid (struct CadetConnection *c, int fwd)
+{
+ struct CadetFlowControl *fc;
+
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+
+ return fc->last_pid_sent + 1;
+}
+
+
+/**
+ * Allow the connection to advertise a buffer of the given size.
+ *
+ * The connection will send an @c fwd ACK message (so: in direction !fwd)
+ * allowing up to last_pid_recv + buffer.
+ *
+ * @param c Connection.
+ * @param buffer How many more messages the connection can accept.
+ * @param fwd Is this about FWD traffic? (The ack will go dest->root).
+ */
+void
+GMC_allow (struct CadetConnection *c, unsigned int buffer, int fwd)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " allowing %s %u messages %s\n",
+ GMC_2s (c), buffer, GM_f2s (fwd));
+ send_ack (c, buffer, fwd, GNUNET_NO);
+}
+
+
+/**
+ * Notify other peers on a connection of a broken link. Mark connections
+ * to destroy after all traffic has been sent.
+ *
+ * @param c Connection on which there has been a disconnection.
+ * @param peer Peer that disconnected.
+ */
+void
+GMC_notify_broken (struct CadetConnection *c,
+ struct CadetPeer *peer)
+{
+ int fwd;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " notify broken on %s due to %s disconnect\n",
+ GMC_2s (c), GMP_2s (peer));
+
+ fwd = peer == get_prev_hop (c);
+
+ if (GNUNET_YES == GMC_is_terminal (c, fwd))
+ {
+ /* Local shutdown, no one to notify about this. */
+ GMC_destroy (c);
+ return;
+ }
+ if (GNUNET_NO == c->destroy)
+ send_broken (c, &my_full_id, GMP_get_id (peer), fwd);
+
+ /* Connection will have at least one pending message
+ * (the one we just scheduled), so no point in checking whether to
+ * destroy immediately. */
+ c->destroy = GNUNET_YES;
+ c->state = CADET_CONNECTION_DESTROYED;
+
+ /**
+ * Cancel all queues, if no message is left, connection will be destroyed.
+ */
+ connection_cancel_queues (c, !fwd);
+
+ return;
+}
+
+
+/**
+ * Is this peer the first one on the connection?
+ *
+ * @param c Connection.
+ * @param fwd Is this about fwd traffic?
+ *
+ * @return #GNUNET_YES if origin, #GNUNET_NO if relay/terminal.
+ */
+int
+GMC_is_origin (struct CadetConnection *c, int fwd)
+{
+ if (!fwd && c->path->length - 1 == c->own_pos )
+ return GNUNET_YES;
+ if (fwd && 0 == c->own_pos)
+ return GNUNET_YES;
+ return GNUNET_NO;
+}
+
+
+/**
+ * Is this peer the last one on the connection?
+ *
+ * @param c Connection.
+ * @param fwd Is this about fwd traffic?
+ * Note that the ROOT is the terminal for BCK traffic!
+ *
+ * @return #GNUNET_YES if terminal, #GNUNET_NO if relay/origin.
+ */
+int
+GMC_is_terminal (struct CadetConnection *c, int fwd)
+{
+ return GMC_is_origin (c, !fwd);
+}
+
+
+/**
+ * See if we are allowed to send by the next hop in the given direction.
+ *
+ * @param c Connection.
+ * @param fwd Is this about fwd traffic?
+ *
+ * @return #GNUNET_YES in case it's OK to send.
+ */
+int
+GMC_is_sendable (struct CadetConnection *c, int fwd)
+{
+ struct CadetFlowControl *fc;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " checking sendability of %s traffic on %s\n",
+ GM_f2s (fwd), GMC_2s (c));
+ if (NULL == c)
+ {
+ GNUNET_break (0);
+ return GNUNET_YES;
+ }
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " last ack recv: %u, last pid sent: %u\n",
+ fc->last_ack_recv, fc->last_pid_sent);
+ if (GM_is_pid_bigger (fc->last_ack_recv, fc->last_pid_sent))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " sendable\n");
+ return GNUNET_YES;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " not sendable\n");
+ return GNUNET_NO;
+}
+
+
+/**
+ * Check if this connection is a direct one (never trim a direct connection).
+ *
+ * @param c Connection.
+ *
+ * @return #GNUNET_YES in case it's a direct connection, #GNUNET_NO otherwise.
+ */
+int
+GMC_is_direct (struct CadetConnection *c)
+{
+ return (c->path->length == 2) ? GNUNET_YES : GNUNET_NO;
+}
+
+/**
+ * Sends an already built message on a connection, properly registering
+ * all used resources.
+ *
+ * @param message Message to send. Function makes a copy of it.
+ * If message is not hop-by-hop, decrements TTL of copy.
+ * @param payload_type Type of payload, in case the message is encrypted.
+ * @param c Connection on which this message is transmitted.
+ * @param fwd Is this a fwd message?
+ * @param force Force the connection to accept the message (buffer overfill).
+ * @param cont Continuation called once message is sent. Can be NULL.
+ * @param cont_cls Closure for @c cont.
+ *
+ * @return Handle to cancel the message before it's sent.
+ * NULL on error or if @c cont is NULL.
+ * Invalid on @c cont call.
+ */
+struct CadetConnectionQueue *
+GMC_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
+ uint16_t payload_type, uint32_t payload_id,
+ struct CadetConnection *c, int fwd, int force,
+ GMC_sent cont, void *cont_cls)
+{
+ struct CadetFlowControl *fc;
+ struct CadetConnectionQueue *q;
+ void *data;
+ size_t size;
+ uint16_t type;
+ int droppable;
+
+ size = ntohs (message->size);
+ data = GNUNET_malloc (size);
+ memcpy (data, message, size);
+ type = ntohs (message->type);
+ LOG (GNUNET_ERROR_TYPE_INFO, "--> %s (%s %u) on connection %s (%u bytes)\n",
+ GM_m2s (type), GM_m2s (payload_type), payload_id, GMC_2s (c), size);
+
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ droppable = GNUNET_NO == force;
+ switch (type)
+ {
+ struct GNUNET_CADET_Encrypted *emsg;
+ struct GNUNET_CADET_KX *kmsg;
+ struct GNUNET_CADET_ACK *amsg;
+ struct GNUNET_CADET_Poll *pmsg;
+ struct GNUNET_CADET_ConnectionDestroy *dmsg;
+ struct GNUNET_CADET_ConnectionBroken *bmsg;
+ uint32_t ttl;
+
+ case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
+ emsg = (struct GNUNET_CADET_Encrypted *) data;
+ ttl = ntohl (emsg->ttl);
+ if (0 == ttl)
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (data);
+ return NULL;
+ }
+ emsg->cid = c->id;
+ emsg->ttl = htonl (ttl - 1);
+ emsg->pid = htonl (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Q_N+ %p %u\n", fc, fc->queue_n);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "last pid sent %u\n", fc->last_pid_sent);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ack recv %u\n", fc->last_ack_recv);
+ if (GNUNET_YES == droppable)
+ {
+ fc->queue_n++;
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " not droppable, Q_N stays the same\n");
+ }
+ if (GM_is_pid_bigger (fc->last_pid_sent + 1, fc->last_ack_recv))
+ {
+ GMC_start_poll (c, fwd);
+ }
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_KX:
+ kmsg = (struct GNUNET_CADET_KX *) data;
+ kmsg->cid = c->id;
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_ACK:
+ amsg = (struct GNUNET_CADET_ACK *) data;
+ amsg->cid = c->id;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ack %u\n", ntohl (amsg->ack));
+ droppable = GNUNET_NO;
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_POLL:
+ pmsg = (struct GNUNET_CADET_Poll *) data;
+ pmsg->cid = c->id;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " poll %u\n", ntohl (pmsg->pid));
+ droppable = GNUNET_NO;
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
+ dmsg = (struct GNUNET_CADET_ConnectionDestroy *) data;
+ dmsg->cid = c->id;
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
+ bmsg = (struct GNUNET_CADET_ConnectionBroken *) data;
+ bmsg->cid = c->id;
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE:
+ GNUNET_break (0);
+ /* falltrough */
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK:
+ break;
+
+ default:
+ GNUNET_break (0);
+ GNUNET_free (data);
+ return NULL;
+ }
+
+ if (fc->queue_n > fc->queue_max && droppable)
+ {
+ GNUNET_STATISTICS_update (stats, "# messages dropped (buffer full)",
+ 1, GNUNET_NO);
+ GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "queue full: %u/%u\n",
+ fc->queue_n, fc->queue_max);
+ if (GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED == type)
+ {
+ fc->queue_n--;
+ }
+ GNUNET_free (data);
+ return NULL; /* Drop this message */
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %p %u\n", c, c->pending_messages);
+// c->pending_messages++;
+
+ q = GNUNET_new (struct CadetConnectionQueue);
+ q->forced = !droppable;
+ q->q = GMP_queue_add (get_hop (c, fwd), data, type, payload_type, payload_id,
+ size, c, fwd, &conn_message_sent, q);
+ if (NULL == q->q)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING dropping msg on %s\n", GMC_2s (c));
+ GNUNET_free (data);
+ GNUNET_free (q);
+ return NULL;
+ }
+ q->cont = cont;
+ q->cont_cls = cont_cls;
+ return (NULL == cont) ? NULL : q;
+}
+
+
+/**
+ * Cancel a previously sent message while it's in the queue.
+ *
+ * ONLY can be called before the continuation given to the send function
+ * is called. Once the continuation is called, the message is no longer in the
+ * queue.
+ *
+ * @param q Handle to the queue.
+ */
+void
+GMC_cancel (struct CadetConnectionQueue *q)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "! GMC cancel message\n");
+
+ /* queue destroy calls message_sent, which calls q->cont and frees q */
+ GMP_queue_destroy (q->q, GNUNET_YES, GNUNET_NO, 0);
+}
+
+
+/**
+ * Sends a CREATE CONNECTION message for a path to a peer.
+ * Changes the connection and tunnel states if necessary.
+ *
+ * @param connection Connection to create.
+ */
+void
+GMC_send_create (struct CadetConnection *connection)
+{
+ enum CadetTunnel3CState state;
+ size_t size;
+
+ size = sizeof (struct GNUNET_CADET_ConnectionCreate);
+ size += connection->path->length * sizeof (struct GNUNET_PeerIdentity);
+
+ LOG (GNUNET_ERROR_TYPE_INFO, "===> %s on connection %s (%u bytes)\n",
+ GM_m2s (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE),
+ GMC_2s (connection), size);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %p %u (create)\n",
+ connection, connection->pending_messages);
+ connection->pending_messages++;
+
+ connection->maintenance_q =
+ GMP_queue_add (get_next_hop (connection), NULL,
+ GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE,
+ GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, 0,
+ size, connection, GNUNET_YES, &conn_message_sent, NULL);
+
+ state = GMT_get_cstate (connection->t);
+ if (CADET_TUNNEL3_SEARCHING == state || CADET_TUNNEL3_NEW == state)
+ GMT_change_cstate (connection->t, CADET_TUNNEL3_WAITING);
+ if (CADET_CONNECTION_NEW == connection->state)
+ connection_change_state (connection, CADET_CONNECTION_SENT);
+}
+
+
+/**
+ * Send a message to all peers in this connection that the connection
+ * is no longer valid.
+ *
+ * If some peer should not receive the message, it should be zero'ed out
+ * before calling this function.
+ *
+ * @param c The connection whose peers to notify.
+ */
+void
+GMC_send_destroy (struct CadetConnection *c)
+{
+ struct GNUNET_CADET_ConnectionDestroy msg;
+
+ if (GNUNET_YES == c->destroy)
+ return;
+
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);;
+ msg.cid = c->id;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " sending connection destroy for connection %s\n",
+ GMC_2s (c));
+
+ if (GNUNET_NO == GMC_is_terminal (c, GNUNET_YES))
+ GMC_send_prebuilt_message (&msg.header,
+ GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY, 0,
+ c, GNUNET_YES, GNUNET_YES, NULL, NULL);
+ if (GNUNET_NO == GMC_is_terminal (c, GNUNET_NO))
+ GMC_send_prebuilt_message (&msg.header,
+ GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY, 0,
+ c, GNUNET_NO, GNUNET_YES, NULL, NULL);
+ c->destroy = GNUNET_YES;
+ c->state = CADET_CONNECTION_DESTROYED;
+}
+
+
+/**
+ * @brief Start a polling timer for the connection.
+ *
+ * When a neighbor does not accept more traffic on the connection it could be
+ * caused by a simple congestion or by a lost ACK. Polling enables to check
+ * for the lastest ACK status for a connection.
+ *
+ * @param c Connection.
+ * @param fwd Should we poll in the FWD direction?
+ */
+void
+GMC_start_poll (struct CadetConnection *c, int fwd)
+{
+ struct CadetFlowControl *fc;
+
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL %s requested\n",
+ GM_f2s (fwd));
+ if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task || NULL != fc->poll_msg)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** not needed (%u, %p)\n",
+ fc->poll_task, fc->poll_msg);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL started on request\n");
+ fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time,
+ &connection_poll,
+ fc);
+}
+
+
+/**
+ * @brief Stop polling a connection for ACKs.
+ *
+ * Once we have enough ACKs for future traffic, polls are no longer necessary.
+ *
+ * @param c Connection.
+ * @param fwd Should we stop the poll in the FWD direction?
+ */
+void
+GMC_stop_poll (struct CadetConnection *c, int fwd)
+{
+ struct CadetFlowControl *fc;
+
+ fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task)
+ {
+ GNUNET_SCHEDULER_cancel (fc->poll_task);
+ fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+}
+
+/**
+ * Get a (static) string for a connection.
+ *
+ * @param c Connection.
+ */
+const char *
+GMC_2s (const struct CadetConnection *c)
+{
+ if (NULL == c)
+ return "NULL";
+
+ if (NULL != c->t)
+ {
+ static char buf[128];
+
+ sprintf (buf, "%s (->%s)",
+ GNUNET_h2s (GM_h2hc (GMC_get_id (c))), GMT_2s (c->t));
+ return buf;
+ }
+ return GNUNET_h2s (GM_h2hc (&c->id));
+}
Copied: gnunet/src/cadet/gnunet-service-cadet_connection.h (from rev 33185,
gnunet/src/mesh/gnunet-service-cadet_connection.h)
===================================================================
--- gnunet/src/cadet/gnunet-service-cadet_connection.h
(rev 0)
+++ gnunet/src/cadet/gnunet-service-cadet_connection.h 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -0,0 +1,566 @@
+/*
+ This file is part of GNUnet.
+ (C) 2013 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_connection.h
+ * @brief cadet service; dealing with connections
+ * @author Bartlomiej Polot
+ *
+ * All functions in this file should use the prefix GMC (Gnunet Cadet
Connection)
+ */
+
+#ifndef GNUNET_SERVICE_CADET_CONNECTION_H
+#define GNUNET_SERVICE_CADET_CONNECTION_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0 /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include "gnunet_util_lib.h"
+
+
+/**
+ * All the states a connection can be in.
+ */
+enum CadetConnectionState
+{
+ /**
+ * Uninitialized status, should never appear in operation.
+ */
+ CADET_CONNECTION_NEW,
+
+ /**
+ * Connection create message sent, waiting for ACK.
+ */
+ CADET_CONNECTION_SENT,
+
+ /**
+ * Connection ACK sent, waiting for ACK.
+ */
+ CADET_CONNECTION_ACK,
+
+ /**
+ * Connection confirmed, ready to carry traffic.
+ */
+ CADET_CONNECTION_READY,
+
+ /**
+ * Connection to be destroyed, just waiting to empty queues.
+ */
+ CADET_CONNECTION_DESTROYED,
+};
+
+
+/**
+ * Struct containing all information regarding a connection to a peer.
+ */
+struct CadetConnection;
+
+/**
+ * Handle for messages queued but not yet sent.
+ */
+struct CadetConnectionQueue;
+
+#include "cadet_path.h"
+#include "gnunet-service-cadet_channel.h"
+#include "gnunet-service-cadet_peer.h"
+
+
+
+/**
+ * Callback called when a queued message is sent.
+ *
+ * @param cls Closure.
+ * @param c Connection this message was on.
+ * @param type Type of message sent.
+ * @param fwd Was this a FWD going message?
+ * @param size Size of the message.
+ */
+typedef void (*GMC_sent) (void *cls,
+ struct CadetConnection *c,
+ struct CadetConnectionQueue *q,
+ uint16_t type, int fwd, size_t size);
+
+/**
+ * Core handler for connection creation.
+ *
+ * @param cls Closure (unused).
+ * @param peer Sender (neighbor).
+ * @param message Message.
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+int
+GMC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message);
+
+/**
+ * Core handler for path confirmations.
+ *
+ * @param cls closure
+ * @param message message
+ * @param peer peer identity this notification is about
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+int
+GMC_handle_confirm (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message);
+
+/**
+ * Core handler for notifications of broken paths
+ *
+ * @param cls Closure (unused).
+ * @param id Peer identity of sending neighbor.
+ * @param message Message.
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+int
+GMC_handle_broken (void* cls,
+ const struct GNUNET_PeerIdentity* id,
+ const struct GNUNET_MessageHeader* message);
+
+/**
+ * Core handler for tunnel destruction
+ *
+ * @param cls Closure (unused).
+ * @param peer Peer identity of sending neighbor.
+ * @param message Message.
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+int
+GMC_handle_destroy (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message);
+
+/**
+ * Core handler for encrypted cadet network traffic (channel mgmt, data).
+ *
+ * @param cls Closure (unused).
+ * @param message Message received.
+ * @param peer Peer who sent the message.
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+int
+GMC_handle_encrypted (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message);
+
+/**
+ * Core handler for key exchange traffic (ephemeral key, ping, pong).
+ *
+ * @param cls Closure (unused).
+ * @param message Message received.
+ * @param peer Peer who sent the message.
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+int
+GMC_handle_kx (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message);
+
+/**
+ * Core handler for cadet network traffic point-to-point acks.
+ *
+ * @param cls closure
+ * @param message message
+ * @param peer peer identity this notification is about
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+int
+GMC_handle_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message);
+
+/**
+ * Core handler for cadet network traffic point-to-point ack polls.
+ *
+ * @param cls closure
+ * @param message message
+ * @param peer peer identity this notification is about
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+int
+GMC_handle_poll (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message);
+
+/**
+ * Core handler for cadet keepalives.
+ *
+ * @param cls closure
+ * @param message message
+ * @param peer peer identity this notification is about
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ *
+ * TODO: Check who we got this from, to validate route.
+ */
+int
+GMC_handle_keepalive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message);
+
+/**
+ * Send an ACK on the appropriate connection/channel, depending on
+ * the direction and the position of the peer.
+ *
+ * @param c Which connection to send the hop-by-hop ACK.
+ * @param fwd Is this a fwd ACK? (will go dest->root).
+ * @param force Send the ACK even if suboptimal (e.g. requested by POLL).
+ */
+void
+GMC_send_ack (struct CadetConnection *c, int fwd, int force);
+
+/**
+ * Initialize the connections subsystem
+ *
+ * @param c Configuration handle.
+ */
+void
+GMC_init (const struct GNUNET_CONFIGURATION_Handle *c);
+
+/**
+ * Shut down the connections subsystem.
+ */
+void
+GMC_shutdown (void);
+
+/**
+ * Create a connection.
+ *
+ * @param cid Connection ID (either created locally or imposed remotely).
+ * @param t Tunnel this connection belongs to (or NULL);
+ * @param p Path this connection has to use.
+ * @param own_pos Own position in the @c p path.
+ *
+ * @return Newly created connection, NULL in case of error (own id not in
path).
+ */
+struct CadetConnection *
+GMC_new (const struct GNUNET_CADET_Hash *cid,
+ struct CadetTunnel3 *t,
+ struct CadetPeerPath *p,
+ unsigned int own_pos);
+
+/**
+ * Connection is no longer needed: destroy it.
+ *
+ * Cancels all pending traffic (including possible DESTROY messages), all
+ * maintenance tasks and removes the connection from neighbor peers and tunnel.
+ *
+ * @param c Connection to destroy.
+ */
+void
+GMC_destroy (struct CadetConnection *c);
+
+/**
+ * Get the connection ID.
+ *
+ * @param c Connection to get the ID from.
+ *
+ * @return ID of the connection.
+ */
+const struct GNUNET_CADET_Hash *
+GMC_get_id (const struct CadetConnection *c);
+
+
+/**
+ * Get a hash for the connection ID.
+ *
+ * @param c Connection to get the hash.
+ *
+ * @return Hash expanded from the ID of the connection.
+ */
+const struct GNUNET_HashCode *
+GMC_get_h (const struct CadetConnection *c);
+
+
+/**
+ * Get the connection path.
+ *
+ * @param c Connection to get the path from.
+ *
+ * @return path used by the connection.
+ */
+const struct CadetPeerPath *
+GMC_get_path (const struct CadetConnection *c);
+
+/**
+ * Get the connection state.
+ *
+ * @param c Connection to get the state from.
+ *
+ * @return state of the connection.
+ */
+enum CadetConnectionState
+GMC_get_state (const struct CadetConnection *c);
+
+/**
+ * Get the connection tunnel.
+ *
+ * @param c Connection to get the tunnel from.
+ *
+ * @return tunnel of the connection.
+ */
+struct CadetTunnel3 *
+GMC_get_tunnel (const struct CadetConnection *c);
+
+/**
+ * Get free buffer space in a connection.
+ *
+ * @param c Connection.
+ * @param fwd Is query about FWD traffic?
+ *
+ * @return Free buffer space [0 - max_msgs_queue/max_connections]
+ */
+unsigned int
+GMC_get_buffer (struct CadetConnection *c, int fwd);
+
+/**
+ * Get how many messages have we allowed to send to us from a direction.
+ *
+ * @param c Connection.
+ * @param fwd Are we asking about traffic from FWD (BCK messages)?
+ *
+ * @return last_ack_sent - last_pid_recv
+ */
+unsigned int
+GMC_get_allowed (struct CadetConnection *c, int fwd);
+
+/**
+ * Get messages queued in a connection.
+ *
+ * @param c Connection.
+ * @param fwd Is query about FWD traffic?
+ *
+ * @return Number of messages queued.
+ */
+unsigned int
+GMC_get_qn (struct CadetConnection *c, int fwd);
+
+/**
+ * Get next PID to use.
+ *
+ * @param c Connection.
+ * @param fwd Is query about FWD traffic?
+ *
+ * @return Last PID used + 1.
+ */
+unsigned int
+GMC_get_pid (struct CadetConnection *c, int fwd);
+
+/**
+ * Allow the connection to advertise a buffer of the given size.
+ *
+ * The connection will send an @c fwd ACK message (so: in direction !fwd)
+ * allowing up to last_pid_recv + buffer.
+ *
+ * @param c Connection.
+ * @param buffer How many more messages the connection can accept.
+ * @param fwd Is this about FWD traffic? (The ack will go dest->root).
+ */
+void
+GMC_allow (struct CadetConnection *c, unsigned int buffer, int fwd);
+
+/**
+ * Send FWD keepalive packets for a connection.
+ *
+ * @param cls Closure (connection for which to send the keepalive).
+ * @param tc Notification context.
+ */
+void
+GMC_fwd_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+/**
+ * Send BCK keepalive packets for a connection.
+ *
+ * @param cls Closure (connection for which to send the keepalive).
+ * @param tc Notification context.
+ */
+void
+GMC_bck_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Notify other peers on a connection of a broken link. Mark connections
+ * to destroy after all traffic has been sent.
+ *
+ * @param c Connection on which there has been a disconnection.
+ * @param peer Peer that disconnected.
+ */
+void
+GMC_notify_broken (struct CadetConnection *c,
+ struct CadetPeer *peer);
+
+/**
+ * Is this peer the first one on the connection?
+ *
+ * @param c Connection.
+ * @param fwd Is this about fwd traffic?
+ *
+ * @return #GNUNET_YES if origin, #GNUNET_NO if relay/terminal.
+ */
+int
+GMC_is_origin (struct CadetConnection *c, int fwd);
+
+/**
+ * Is this peer the last one on the connection?
+ *
+ * @param c Connection.
+ * @param fwd Is this about fwd traffic?
+ * Note that the ROOT is the terminal for BCK traffic!
+ *
+ * @return #GNUNET_YES if terminal, #GNUNET_NO if relay/origin.
+ */
+int
+GMC_is_terminal (struct CadetConnection *c, int fwd);
+
+/**
+ * See if we are allowed to send by the next hop in the given direction.
+ *
+ * @param c Connection.
+ * @param fwd Is this about fwd traffic?
+ *
+ * @return #GNUNET_YES in case it's OK to send.
+ */
+int
+GMC_is_sendable (struct CadetConnection *c, int fwd);
+
+/**
+ * Check if this connection is a direct one (never trim a direct connection).
+ *
+ * @param c Connection.
+ *
+ * @return #GNUNET_YES in case it's a direct connection, #GNUNET_NO otherwise.
+ */
+int
+GMC_is_direct (struct CadetConnection *c);
+
+/**
+ * Cancel a previously sent message while it's in the queue.
+ *
+ * ONLY can be called before the continuation given to the send function
+ * is called. Once the continuation is called, the message is no longer in the
+ * queue.
+ *
+ * @param q Handle to the queue.
+ */
+void
+GMC_cancel (struct CadetConnectionQueue *q);
+
+/**
+ * Sends an already built message on a connection, properly registering
+ * all used resources.
+ *
+ * @param message Message to send. Function makes a copy of it.
+ * If message is not hop-by-hop, decrements TTL of copy.
+ * @param payload_type Type of payload, in case the message is encrypted.
+ * @param c Connection on which this message is transmitted.
+ * @param fwd Is this a fwd message?
+ * @param force Force the connection to accept the message (buffer overfill).
+ * @param cont Continuation called once message is sent. Can be NULL.
+ * @param cont_cls Closure for @c cont.
+ *
+ * @return Handle to cancel the message before it's sent.
+ * NULL on error or if @c cont is NULL.
+ * Invalid on @c cont call.
+ */
+struct CadetConnectionQueue *
+GMC_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
+ uint16_t payload_type, uint32_t payload_id,
+ struct CadetConnection *c, int fwd, int force,
+ GMC_sent cont, void *cont_cls);
+
+/**
+ * Sends a CREATE CONNECTION message for a path to a peer.
+ * Changes the connection and tunnel states if necessary.
+ *
+ * @param connection Connection to create.
+ */
+void
+GMC_send_create (struct CadetConnection *connection);
+
+/**
+ * Send a message to all peers in this connection that the connection
+ * is no longer valid.
+ *
+ * If some peer should not receive the message, it should be zero'ed out
+ * before calling this function.
+ *
+ * @param c The connection whose peers to notify.
+ */
+void
+GMC_send_destroy (struct CadetConnection *c);
+
+/**
+ * @brief Start a polling timer for the connection.
+ *
+ * When a neighbor does not accept more traffic on the connection it could be
+ * caused by a simple congestion or by a lost ACK. Polling enables to check
+ * for the lastest ACK status for a connection.
+ *
+ * @param c Connection.
+ * @param fwd Should we poll in the FWD direction?
+ */
+void
+GMC_start_poll (struct CadetConnection *c, int fwd);
+
+
+/**
+ * @brief Stop polling a connection for ACKs.
+ *
+ * Once we have enough ACKs for future traffic, polls are no longer necessary.
+ *
+ * @param c Connection.
+ * @param fwd Should we stop the poll in the FWD direction?
+ */
+void
+GMC_stop_poll (struct CadetConnection *c, int fwd);
+
+/**
+ * Get a (static) string for a connection.
+ *
+ * @param c Connection.
+ */
+const char *
+GMC_2s (const struct CadetConnection *c);
+
+#if 0 /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* ifndef GNUNET_SERVICE_CADET_CONNECTION_H */
+#endif
+/* end of gnunet-service-cadet_connection.h */
Copied: gnunet/src/cadet/gnunet-service-cadet_dht.c (from rev 33185,
gnunet/src/mesh/gnunet-service-cadet_dht.c)
===================================================================
--- gnunet/src/cadet/gnunet-service-cadet_dht.c (rev 0)
+++ gnunet/src/cadet/gnunet-service-cadet_dht.c 2014-05-07 12:07:16 UTC (rev
33186)
@@ -0,0 +1,423 @@
+/*
+ This file is part of GNUnet.
+ (C) 2013 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+#include "gnunet_dht_service.h"
+#include "gnunet_statistics_service.h"
+
+#include "cadet_path.h"
+#include "gnunet-service-cadet_dht.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_hello.h"
+
+#define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__)
+
+
+/******************************************************************************/
+/******************************** STRUCTS
**********************************/
+/******************************************************************************/
+
+/**
+ * Handle for DHT searches.
+ */
+struct GMD_search_handle
+{
+ /** DHT_GET handle. */
+ struct GNUNET_DHT_GetHandle *dhtget;
+
+ /** Provided callback to call when a path is found. */
+ GMD_search_callback callback;
+
+ /** Provided closure. */
+ void *cls;
+
+ /** Peer ID searched for */
+ GNUNET_PEER_Id peer_id;
+};
+
+
+/******************************************************************************/
+/******************************* GLOBALS
***********************************/
+/******************************************************************************/
+
+/**
+ * Global handle to the statistics service.
+ */
+extern struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Own ID (short value).
+ */
+extern GNUNET_PEER_Id myid;
+
+/**
+ * Own ID (full value).
+ */
+extern struct GNUNET_PeerIdentity my_full_id;
+
+/**
+ * Handle to use DHT.
+ */
+static struct GNUNET_DHT_Handle *dht_handle;
+
+/**
+ * How often to PUT own ID in the DHT.
+ */
+static struct GNUNET_TIME_Relative id_announce_time;
+
+/**
+ * DHT replication level, see DHT API: GNUNET_DHT_get_start, GNUNET_DHT_put.
+ */
+static unsigned long long dht_replication_level;
+
+/**
+ * Task to periodically announce itself in the network.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier announce_id_task;
+
+/**
+ * GET requests to stop on shutdown.
+ */
+static struct GNUNET_CONTAINER_MultiHashMap32 *get_requests;
+
+/******************************************************************************/
+/******************************** STATIC
***********************************/
+/******************************************************************************/
+
+
+/**
+ * Build a PeerPath from the paths returned from the DHT, reversing the paths
+ * to obtain a local peer -> destination path and interning the peer ids.
+ *
+ * @return Newly allocated and created path
+ *
+ * FIXME refactor and use build_path_from_peer_ids
+ */
+static struct CadetPeerPath *
+path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
+ unsigned int get_path_length,
+ const struct GNUNET_PeerIdentity *put_path,
+ unsigned int put_path_length)
+{
+ struct CadetPeerPath *p;
+ GNUNET_PEER_Id id;
+ int i;
+
+ p = path_new (1);
+ p->peers[0] = myid;
+ GNUNET_PEER_change_rc (myid, 1);
+ i = get_path_length;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " GET has %d hops.\n", i);
+ for (i--; i >= 0; i--)
+ {
+ id = GNUNET_PEER_intern (&get_path[i]);
+ if (p->length > 0 && id == p->peers[p->length - 1])
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n");
+ GNUNET_PEER_change_rc (id, -1);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Adding from GET: %s.\n",
+ GNUNET_i2s (&get_path[i]));
+ p->length++;
+ p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) *
p->length);
+ p->peers[p->length - 1] = id;
+ }
+ }
+ i = put_path_length;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " PUT has %d hops.\n", i);
+ for (i--; i >= 0; i--)
+ {
+ id = GNUNET_PEER_intern (&put_path[i]);
+ if (id == myid)
+ {
+ /* PUT path went through us, so discard the path up until now and start
+ * from here to get a much shorter (and loop-free) path.
+ */
+ path_destroy (p);
+ p = path_new (0);
+ }
+ if (p->length > 0 && id == p->peers[p->length - 1])
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n");
+ GNUNET_PEER_change_rc (id, -1);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Adding from PUT: %s.\n",
+ GNUNET_i2s (&put_path[i]));
+ p->length++;
+ p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) *
p->length);
+ p->peers[p->length - 1] = id;
+ }
+ }
+#if CADET_DEBUG
+ if (get_path_length > 0)
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " (first of GET: %s)\n",
+ GNUNET_i2s (&get_path[0]));
+ if (put_path_length > 0)
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " (first of PUT: %s)\n",
+ GNUNET_i2s (&put_path[0]));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " In total: %d hops\n",
+ p->length);
+ for (i = 0; i < p->length; i++)
+ {
+ struct GNUNET_PeerIdentity peer_id;
+
+ GNUNET_PEER_resolve (p->peers[i], &peer_id);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " %u: %s\n", p->peers[i],
+ GNUNET_i2s (&peer_id));
+ }
+#endif
+ return p;
+}
+
+
+/**
+ * Function to process paths received for a new peer addition. The recorded
+ * paths form the initial tunnel, which can be optimized later.
+ * Called on each result obtained for the DHT search.
+ *
+ * @param cls closure
+ * @param exp when will this value expire
+ * @param key key of the result
+ * @param get_path path of the get request
+ * @param get_path_length lenght of get_path
+ * @param put_path path of the put request
+ * @param put_path_length length of the put_path
+ * @param type type of the result
+ * @param size number of bytes in data
+ * @param data pointer to the result data
+ */
+static void
+dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
+ const struct GNUNET_HashCode * key,
+ const struct GNUNET_PeerIdentity *get_path,
+ unsigned int get_path_length,
+ const struct GNUNET_PeerIdentity *put_path,
+ unsigned int put_path_length, enum GNUNET_BLOCK_Type type,
+ size_t size, const void *data)
+{
+ struct GMD_search_handle *h = cls;
+ struct GNUNET_HELLO_Message *hello;
+ struct CadetPeerPath *p;
+ struct CadetPeer *peer;
+ char *s;
+
+ p = path_build_from_dht (get_path, get_path_length,
+ put_path, put_path_length);
+ s = path_2s (p);
+ LOG (GNUNET_ERROR_TYPE_INFO, "Got path from DHT: %s\n", s);
+ GNUNET_free_non_null (s);
+ peer = GMP_get_short (p->peers[p->length - 1]);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Got HELLO for %s\n", GMP_2s (peer));
+ h->callback (h->cls, p);
+ path_destroy (p);
+ hello = (struct GNUNET_HELLO_Message *) data;
+ GMP_set_hello (peer, hello);
+ GMP_try_connect (peer);
+ return;
+}
+
+
+/**
+ * Periodically announce self id in the DHT
+ *
+ * @param cls closure
+ * @param tc task context
+ */
+static void
+announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_HashCode phash;
+ const struct GNUNET_HELLO_Message *hello;
+ size_t size;
+ struct GNUNET_TIME_Absolute expiration;
+ struct GNUNET_TIME_Relative retry_time;
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ {
+ announce_id_task = GNUNET_SCHEDULER_NO_TASK;
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Announce ID\n");
+
+ /* TODO
+ * - Set data expiration in function of X
+ * - Adapt X to churn
+ */
+ hello = GMH_get_mine ();
+ if (NULL == hello || (size = GNUNET_HELLO_size (hello)) == 0)
+ {
+ /* Peerinfo gave us no hello yet, try again in a second. */
+ announce_id_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+ &announce_id, cls);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " no hello, waiting!\n");
+ return;
+ }
+ expiration = GNUNET_HELLO_get_last_expiration (hello);
+ retry_time = GNUNET_TIME_absolute_get_remaining (expiration);
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Hello %p size: %u\n", hello, size);
+ memset (&phash, 0, sizeof (phash));
+ memcpy (&phash, &my_full_id, sizeof (my_full_id));
+ GNUNET_DHT_put (dht_handle, /* DHT handle */
+ &phash, /* Key to use */
+ dht_replication_level, /* Replication level */
+ GNUNET_DHT_RO_RECORD_ROUTE
+ | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */
+ GNUNET_BLOCK_TYPE_DHT_HELLO, /* Block type */
+ size, /* Size of the data */
+ (const char *) hello, /* Data itself */
+ expiration, /* Data expiration */
+ retry_time, /* Retry time */
+ NULL, /* Continuation */
+ NULL); /* Continuation closure */
+ announce_id_task =
+ GNUNET_SCHEDULER_add_delayed (id_announce_time, &announce_id, cls);
+}
+
+/**
+ * Iterator over hash map entries and stop GET requests before disconnecting
+ * from the DHT.
+ *
+ * @param cls Closure (unused)
+ * @param key Current peer ID.
+ * @param value Value in the hash map (GMD_search_handle).
+ *
+ * @return #GNUNET_YES, we should continue to iterate,
+ */
+int
+stop_get (void *cls,
+ uint32_t key,
+ void *value)
+{
+ struct GMD_search_handle *h = value;
+
+ GMD_search_stop (h);
+ return GNUNET_YES;
+}
+
+
+/******************************************************************************/
+/******************************** API
***********************************/
+/******************************************************************************/
+
+/**
+ * Initialize the DHT subsystem.
+ *
+ * @param c Configuration.
+ */
+void
+GMD_init (const struct GNUNET_CONFIGURATION_Handle *c)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (c, "CADET",
"DHT_REPLICATION_LEVEL",
+ &dht_replication_level))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
+ "CADET", "DHT_REPLICATION_LEVEL", "USING
DEFAULT");
+ dht_replication_level = 3;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (c, "CADET", "ID_ANNOUNCE_TIME",
+ &id_announce_time))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "CADET", "ID_ANNOUNCE_TIME", "MISSING");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ dht_handle = GNUNET_DHT_connect (c, 64);
+ if (NULL == dht_handle)
+ {
+ GNUNET_break (0);
+ }
+
+ announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL);
+ get_requests = GNUNET_CONTAINER_multihashmap32_create (32);
+}
+
+
+/**
+ * Shut down the DHT subsystem.
+ */
+void
+GMD_shutdown (void)
+{
+ GNUNET_CONTAINER_multihashmap32_iterate (get_requests, &stop_get, NULL);
+ GNUNET_CONTAINER_multihashmap32_destroy (get_requests);
+ if (dht_handle != NULL)
+ {
+ GNUNET_DHT_disconnect (dht_handle);
+ dht_handle = NULL;
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != announce_id_task)
+ {
+ GNUNET_SCHEDULER_cancel (announce_id_task);
+ announce_id_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+}
+
+struct GMD_search_handle *
+GMD_search (const struct GNUNET_PeerIdentity *peer_id,
+ GMD_search_callback callback, void *cls)
+{
+ struct GNUNET_HashCode phash;
+ struct GMD_search_handle *h;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " Starting DHT GET for peer %s\n", GNUNET_i2s (peer_id));
+ memset (&phash, 0, sizeof (phash));
+ memcpy (&phash, peer_id, sizeof (*peer_id));
+ h = GNUNET_new (struct GMD_search_handle);
+ h->peer_id = GNUNET_PEER_intern (peer_id);
+ h->callback = callback;
+ h->cls = cls;
+ h->dhtget = GNUNET_DHT_get_start (dht_handle, /* handle */
+ GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */
+ &phash, /* key to search */
+ dht_replication_level, /* replication
level */
+ GNUNET_DHT_RO_RECORD_ROUTE |
+ GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
+ NULL, /* xquery */
+ 0, /* xquery bits */
+ &dht_get_id_handler, h);
+ GNUNET_CONTAINER_multihashmap32_put (get_requests, h->peer_id, h,
+
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+ return h;
+}
+
+void
+GMD_search_stop (struct GMD_search_handle *h)
+{
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap32_remove (get_requests,
+ h->peer_id, h));
+ GNUNET_DHT_get_stop (h->dhtget);
+ GNUNET_free (h);
+}
Copied: gnunet/src/cadet/gnunet-service-cadet_dht.h (from rev 33185,
gnunet/src/mesh/gnunet-service-cadet_dht.h)
===================================================================
--- gnunet/src/cadet/gnunet-service-cadet_dht.h (rev 0)
+++ gnunet/src/cadet/gnunet-service-cadet_dht.h 2014-05-07 12:07:16 UTC (rev
33186)
@@ -0,0 +1,92 @@
+/*
+ This file is part of GNUnet.
+ (C) 2013 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_dht.h
+ * @brief cadet service; dealing with DHT requests and results
+ * @author Bartlomiej Polot
+ *
+ * All functions in this file should use the prefix GMD (Gnunet Cadet Dht)
+ */
+
+#ifndef GNUNET_SERVICE_CADET_DHT_H
+#define GNUNET_SERVICE_CADET_DHT_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0 /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+struct GMD_search_handle;
+
+
+/**
+ * Callback called on each path found over the DHT.
+ *
+ * @param cls Closure.
+ * @param path An unchecked, unoptimized path to the target node.
+ * After callback will no longer be valid!
+ */
+typedef void (*GMD_search_callback) (void *cls,
+ const struct CadetPeerPath *path);
+
+/******************************************************************************/
+/******************************** API
***********************************/
+/******************************************************************************/
+
+/**
+ * Initialize the DHT subsystem.
+ *
+ * @param c Configuration.
+ */
+void
+GMD_init (const struct GNUNET_CONFIGURATION_Handle *c);
+
+/**
+ * Shut down the DHT subsystem.
+ */
+void
+GMD_shutdown (void);
+
+
+struct GMD_search_handle *
+GMD_search (const struct GNUNET_PeerIdentity *peer_id,
+ GMD_search_callback callback, void *cls);
+
+
+void
+GMD_search_stop (struct GMD_search_handle *h);
+
+#if 0 /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* ifndef GNUNET_CADET_SERVICE_LOCAL_H */
+#endif
+/* end of gnunet-cadet-service_LOCAL.h */
\ No newline at end of file
Copied: gnunet/src/cadet/gnunet-service-cadet_hello.c (from rev 33185,
gnunet/src/mesh/gnunet-service-cadet_hello.c)
===================================================================
--- gnunet/src/cadet/gnunet-service-cadet_hello.c
(rev 0)
+++ gnunet/src/cadet/gnunet-service-cadet_hello.c 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -0,0 +1,198 @@
+/*
+ This file is part of GNUnet.
+ (C) 2014 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+#include "gnunet_statistics_service.h"
+#include "gnunet_peerinfo_service.h"
+
+#include "cadet_protocol.h"
+#include "cadet_path.h"
+
+#include "gnunet-service-cadet_hello.h"
+#include "gnunet-service-cadet_peer.h"
+
+#define LOG(level, ...) GNUNET_log_from(level,"cadet-hll",__VA_ARGS__)
+
+
+/******************************************************************************/
+/******************************** STRUCTS
**********************************/
+/******************************************************************************/
+
+
+
+/******************************************************************************/
+/******************************* GLOBALS
***********************************/
+/******************************************************************************/
+
+/**
+ * Global handle to the statistics service.
+ */
+extern struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Local peer own ID (memory efficient handle).
+ */
+extern GNUNET_PEER_Id myid;
+
+/**
+ * Local peer own ID (full value).
+ */
+extern struct GNUNET_PeerIdentity my_full_id;
+
+
+/**
+ * Don't try to recover tunnels if shutting down.
+ */
+extern int shutting_down;
+
+
+/**
+ * Hello message of local peer.
+ */
+const struct GNUNET_HELLO_Message *mine;
+
+/**
+ * Handle to peerinfo service.
+ */
+static struct GNUNET_PEERINFO_Handle *peerinfo;
+
+/**
+ * Iterator context.
+ */
+struct GNUNET_PEERINFO_NotifyContext* nc;
+
+
+/******************************************************************************/
+/******************************** STATIC
***********************************/
+/******************************************************************************/
+
+/**
+ * Process each hello message received from peerinfo.
+ *
+ * @param cls Closure (unused).
+ * @param peer Identity of the peer.
+ * @param hello Hello of the peer.
+ * @param err_msg Error message.
+ */
+static void
+got_hello (void *cls, const struct GNUNET_PeerIdentity *id,
+ const struct GNUNET_HELLO_Message *hello,
+ const char *err_msg)
+{
+ struct CadetPeer *peer;
+
+ if (NULL == id || NULL == hello)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " hello with id %p and msg %p\n", id, hello);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " hello for %s (%d bytes), expires on %s\n",
+ GNUNET_i2s (id), GNUNET_HELLO_size (hello),
+ GNUNET_STRINGS_absolute_time_to_string
(GNUNET_HELLO_get_last_expiration(hello)));
+ peer = GMP_get (id);
+ GMP_set_hello (peer, hello);
+
+ if (GMP_get_short_id (peer) == myid)
+ {
+ mine = GMP_get_hello (peer);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " updated mine to %p\n", mine);
+ }
+}
+
+
+/******************************************************************************/
+/******************************** API
***********************************/
+/******************************************************************************/
+
+/**
+ * Initialize the hello subsystem.
+ *
+ * @param c Configuration.
+ */
+void
+GMH_init (const struct GNUNET_CONFIGURATION_Handle *c)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
+ GNUNET_assert (NULL == nc);
+ peerinfo = GNUNET_PEERINFO_connect (c);
+ nc = GNUNET_PEERINFO_notify (c, GNUNET_NO, &got_hello, NULL);
+}
+
+
+/**
+ * Shut down the hello subsystem.
+ */
+void
+GMH_shutdown ()
+{
+ if (NULL != nc)
+ {
+ GNUNET_PEERINFO_notify_cancel (nc);
+ nc = NULL;
+ }
+ if (NULL != peerinfo)
+ {
+ GNUNET_PEERINFO_disconnect (peerinfo);
+ peerinfo = NULL;
+ }
+}
+
+
+/**
+ * Get own hello message.
+ *
+ * @return Own hello message.
+ */
+const struct GNUNET_HELLO_Message *
+GMH_get_mine (void)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " mine is %p\n", mine);
+ return mine;
+}
+
+
+/**
+ * Get another peer's hello message.
+ *
+ * @param id ID of the peer whose hello message is requested.
+ *
+ * @return Hello message, if any (NULL possible).
+ */
+const struct GNUNET_HELLO_Message *
+GMH_get (const struct GNUNET_PeerIdentity *id)
+{
+ return GMP_get_hello (GMP_get (id));
+}
+
+
+/**
+ * Convert a hello message to a string.
+ *
+ * @param h Hello message.
+ */
+char *
+GMH_2s (const struct GNUNET_HELLO_Message *h)
+{
+ return "hello (TODO)";
+}
+
+
Copied: gnunet/src/cadet/gnunet-service-cadet_hello.h (from rev 33185,
gnunet/src/mesh/gnunet-service-cadet_hello.h)
===================================================================
--- gnunet/src/cadet/gnunet-service-cadet_hello.h
(rev 0)
+++ gnunet/src/cadet/gnunet-service-cadet_hello.h 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -0,0 +1,76 @@
+/*
+ This file is part of GNUnet.
+ (C) 2014 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_hello.h
+ * @brief cadet service; dealing with hello messages
+ * @author Bartlomiej Polot
+ *
+ * All functions in this file should use the prefix GMH (Gnunet Cadet Hello)
+ */
+
+#ifndef GNUNET_SERVICE_CADET_HELLO_H
+#define GNUNET_SERVICE_CADET_HELLO_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0 /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_hello_lib.h"
+
+
+/**
+ * Initialize the hello subsystem.
+ *
+ * @param c Configuration.
+ */
+void
+GMH_init (const struct GNUNET_CONFIGURATION_Handle *c);
+
+/**
+ * Shut down the hello subsystem.
+ */
+void
+GMH_shutdown ();
+
+/**
+ * Get own hello message.
+ *
+ * @return Own hello message.
+ */
+const struct GNUNET_HELLO_Message *
+GMH_get_mine (void);
+
+#if 0 /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* ifndef GNUNET_CADET_SERVICE_HELLO_H */
+#endif
+/* end of gnunet-cadet-service_hello.h */
Copied: gnunet/src/cadet/gnunet-service-cadet_local.c (from rev 33185,
gnunet/src/mesh/gnunet-service-cadet_local.c)
===================================================================
--- gnunet/src/cadet/gnunet-service-cadet_local.c
(rev 0)
+++ gnunet/src/cadet/gnunet-service-cadet_local.c 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -0,0 +1,1242 @@
+/*
+ This file is part of GNUnet.
+ (C) 2013 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+#include "gnunet_statistics_service.h"
+
+#include "cadet.h"
+#include "cadet_protocol.h" /* GNUNET_CADET_Data is shared */
+
+#include "gnunet-service-cadet_local.h"
+#include "gnunet-service-cadet_channel.h"
+
+/* INFO DEBUG */
+#include "gnunet-service-cadet_tunnel.h"
+#include "gnunet-service-cadet_peer.h"
+
+#define LOG(level, ...) GNUNET_log_from(level,"cadet-loc",__VA_ARGS__)
+
+/******************************************************************************/
+/******************************** STRUCTS
**********************************/
+/******************************************************************************/
+
+/**
+ * Struct containing information about a client of the service
+ *
+ * TODO: add a list of 'waiting' ports
+ */
+struct CadetClient
+{
+ /**
+ * Linked list next
+ */
+ struct CadetClient *next;
+
+ /**
+ * Linked list prev
+ */
+ struct CadetClient *prev;
+
+ /**
+ * Tunnels that belong to this client, indexed by local id
+ */
+ struct GNUNET_CONTAINER_MultiHashMap32 *own_channels;
+
+ /**
+ * Tunnels this client has accepted, indexed by incoming local id
+ */
+ struct GNUNET_CONTAINER_MultiHashMap32 *incoming_channels;
+
+ /**
+ * Channel ID for the next incoming channel.
+ */
+ CADET_ChannelNumber next_chid;
+
+ /**
+ * Handle to communicate with the client
+ */
+ struct GNUNET_SERVER_Client *handle;
+
+ /**
+ * Ports that this client has declared interest in.
+ * Indexed by port, contains *Client.
+ */
+ struct GNUNET_CONTAINER_MultiHashMap32 *ports;
+
+ /**
+ * Whether the client is active or shutting down (don't send confirmations
+ * to a client that is shutting down.
+ */
+ int shutting_down;
+
+ /**
+ * ID of the client, mainly for debug messages
+ */
+ unsigned int id;
+};
+
+/******************************************************************************/
+/******************************* GLOBALS
***********************************/
+/******************************************************************************/
+
+/**
+ * Global handle to the statistics service.
+ */
+extern struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Handle to server lib.
+ */
+static struct GNUNET_SERVER_Handle *server_handle;
+
+/**
+ * DLL with all the clients, head.
+ */
+static struct CadetClient *clients_head;
+
+/**
+ * DLL with all the clients, tail.
+ */
+static struct CadetClient *clients_tail;
+
+/**
+ * Next ID to assign to a client.
+ */
+unsigned int next_client_id;
+
+/**
+ * All ports clients of this peer have opened.
+ */
+static struct GNUNET_CONTAINER_MultiHashMap32 *ports;
+
+/**
+ * Notification context, to send messages to local clients.
+ */
+static struct GNUNET_SERVER_NotificationContext *nc;
+
+
+/******************************************************************************/
+/******************************** STATIC
***********************************/
+/******************************************************************************/
+
+/**
+ * Remove client's ports from the global hashmap on disconnect.
+ *
+ * @param cls Closure (unused).
+ * @param key Port.
+ * @param value Client structure.
+ *
+ * @return GNUNET_OK, keep iterating.
+ */
+static int
+client_release_ports (void *cls,
+ uint32_t key,
+ void *value)
+{
+ int res;
+
+ res = GNUNET_CONTAINER_multihashmap32_remove (ports, key, value);
+ if (GNUNET_YES != res)
+ {
+ GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Port %u by client %p was not registered.\n",
+ key, value);
+ }
+ return GNUNET_OK;
+}
+
+
+
+/******************************************************************************/
+/******************************** HANDLES
***********************************/
+/******************************************************************************/
+
+
+/**
+ * Handler for client connection.
+ *
+ * @param cls Closure (unused).
+ * @param client Client handler.
+ */
+static void
+handle_client_connect (void *cls, struct GNUNET_SERVER_Client *client)
+{
+ struct CadetClient *c;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "client connected: %p\n", client);
+ if (NULL == client)
+ return;
+ c = GNUNET_new (struct CadetClient);
+ c->handle = client;
+ c->id = next_client_id++; /* overflow not important: just for debug */
+ c->next_chid = GNUNET_CADET_LOCAL_CHANNEL_ID_SERV;
+ GNUNET_SERVER_client_keep (client);
+ GNUNET_SERVER_client_set_user_context (client, c);
+ GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, c);
+}
+
+
+/**
+ * Iterator for deleting each channel whose client endpoint disconnected.
+ *
+ * @param cls Closure (client that has disconnected).
+ * @param key The local channel id (used to access the hashmap).
+ * @param value The value stored at the key (channel to destroy).
+ *
+ * @return GNUNET_OK, keep iterating.
+ */
+static int
+channel_destroy_iterator (void *cls,
+ uint32_t key,
+ void *value)
+{
+ struct CadetChannel *ch = value;
+ struct CadetClient *c = cls;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " Channel %s destroy, due to client %s shutdown.\n",
+ GMCH_2s (ch), GML_2s (c));
+
+ GMCH_handle_local_destroy (ch, c, key < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV);
+ return GNUNET_OK;
+}
+
+/**
+ * Handler for client disconnection
+ *
+ * @param cls closure
+ * @param client identification of the client; NULL
+ * for the last call when the server is destroyed
+ */
+static void
+handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
+{
+ struct CadetClient *c;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "client disconnected: %p\n", client);
+ if (client == NULL)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " (SERVER DOWN)\n");
+ return;
+ }
+
+ c = GML_client_get (client);
+ if (NULL != c)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "matching client found (%u, %p)\n",
+ c->id, c);
+ GNUNET_SERVER_client_drop (c->handle);
+ c->shutting_down = GNUNET_YES;
+ if (NULL != c->own_channels)
+ {
+ GNUNET_CONTAINER_multihashmap32_iterate (c->own_channels,
+ &channel_destroy_iterator, c);
+ GNUNET_CONTAINER_multihashmap32_destroy (c->own_channels);
+ }
+
+ if (NULL != c->incoming_channels)
+ {
+ GNUNET_CONTAINER_multihashmap32_iterate (c->incoming_channels,
+ &channel_destroy_iterator, c);
+ GNUNET_CONTAINER_multihashmap32_destroy (c->incoming_channels);
+ }
+
+ if (NULL != c->ports)
+ {
+ GNUNET_CONTAINER_multihashmap32_iterate (c->ports,
+ &client_release_ports, c);
+ GNUNET_CONTAINER_multihashmap32_destroy (c->ports);
+ }
+ GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, c);
+ GNUNET_STATISTICS_update (stats, "# clients", -1, GNUNET_NO);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " client free (%p)\n", c);
+ GNUNET_free (c);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, " context NULL!\n");
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "done!\n");
+ return;
+}
+
+
+/**
+ * Handler for new clients
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message, which includes messages the client wants
+ */
+static void
+handle_new_client (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_CADET_ClientConnect *cc_msg;
+ struct CadetClient *c;
+ unsigned int size;
+ uint32_t *p;
+ unsigned int i;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "new client connected %p\n", client);
+
+ /* Check data sanity */
+ size = ntohs (message->size) - sizeof (struct GNUNET_CADET_ClientConnect);
+ cc_msg = (struct GNUNET_CADET_ClientConnect *) message;
+ if (0 != (size % sizeof (uint32_t)))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ size /= sizeof (uint32_t);
+
+ /* Initialize new client structure */
+ c = GNUNET_SERVER_client_get_user_context (client, struct CadetClient);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " client id %u\n", c->id);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " client has %u ports\n", size);
+ if (size > 0)
+ {
+ uint32_t u32;
+
+ p = (uint32_t *) &cc_msg[1];
+ c->ports = GNUNET_CONTAINER_multihashmap32_create (size);
+ for (i = 0; i < size; i++)
+ {
+ u32 = ntohl (p[i]);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " port: %u\n", u32);
+
+ /* store in client's hashmap */
+ GNUNET_CONTAINER_multihashmap32_put (c->ports, u32, c,
+
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+ /* store in global hashmap */
+ /* FIXME only allow one client to have the port open,
+ * have a backup hashmap with waiting clients */
+ GNUNET_CONTAINER_multihashmap32_put (ports, u32, c,
+
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+ }
+ }
+
+ c->own_channels = GNUNET_CONTAINER_multihashmap32_create (32);
+ c->incoming_channels = GNUNET_CONTAINER_multihashmap32_create (32);
+ GNUNET_SERVER_notification_context_add (nc, client);
+ GNUNET_STATISTICS_update (stats, "# clients", 1, GNUNET_NO);
+
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "new client processed\n");
+}
+
+
+/**
+ * Handler for requests of new tunnels
+ *
+ * @param cls Closure.
+ * @param client Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_channel_create (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct CadetClient *c;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "new channel requested\n");
+
+ /* Sanity check for client registration */
+ if (NULL == (c = GML_client_get (client)))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id);
+
+ /* Message size sanity check */
+ if (sizeof (struct GNUNET_CADET_ChannelMessage) != ntohs (message->size))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+
+ if (GNUNET_OK !=
+ GMCH_handle_local_create (c,
+ (struct GNUNET_CADET_ChannelMessage *)
message))
+ {
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+}
+
+
+/**
+ * Handler for requests of deleting tunnels
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_channel_destroy (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_CADET_ChannelMessage *msg;
+ struct CadetClient *c;
+ struct CadetChannel *ch;
+ CADET_ChannelNumber chid;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a DESTROY CHANNEL from client!\n");
+
+ /* Sanity check for client registration */
+ if (NULL == (c = GML_client_get (client)))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id);
+
+ /* Message sanity check */
+ if (sizeof (struct GNUNET_CADET_ChannelMessage) != ntohs (message->size))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+
+ msg = (struct GNUNET_CADET_ChannelMessage *) message;
+
+ /* Retrieve tunnel */
+ chid = ntohl (msg->channel_id);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " for channel %X\n", chid);
+ ch = GML_channel_get (c, chid);
+ if (NULL == ch)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " channel %X not found\n", chid);
+ GNUNET_STATISTICS_update (stats,
+ "# client destroy messages on unknown channel",
+ 1, GNUNET_NO);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+
+ GMCH_handle_local_destroy (ch, c, chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV);
+
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+}
+
+
+/**
+ * Handler for client traffic
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_data (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_CADET_LocalData *msg;
+ struct CadetClient *c;
+ struct CadetChannel *ch;
+ CADET_ChannelNumber chid;
+ size_t size;
+ int fwd;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Got data from a client!\n");
+
+ /* Sanity check for client registration */
+ if (NULL == (c = GML_client_get (client)))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id);
+
+ msg = (struct GNUNET_CADET_LocalData *) message;
+
+ /* Sanity check for message size */
+ size = ntohs (message->size) - sizeof (struct GNUNET_CADET_LocalData);
+ if (size < sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+
+ /* Channel exists? */
+ chid = ntohl (msg->id);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X\n", chid);
+ fwd = chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV;
+ ch = GML_channel_get (c, chid);
+ if (NULL == ch)
+ {
+ GNUNET_STATISTICS_update (stats,
+ "# client data messages on unknown channel",
+ 1, GNUNET_NO);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+
+ if (GNUNET_OK !=
+ GMCH_handle_local_data (ch, c,
+ (struct GNUNET_MessageHeader *)&msg[1], fwd))
+ {
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "receive done OK\n");
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+
+ return;
+}
+
+
+/**
+ * Handler for client's ACKs for payload traffic.
+ *
+ * @param cls Closure (unused).
+ * @param client Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_ack (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_CADET_LocalAck *msg;
+ struct CadetChannel *ch;
+ struct CadetClient *c;
+ CADET_ChannelNumber chid;
+ int fwd;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a local ACK\n");
+
+ /* Sanity check for client registration */
+ if (NULL == (c = GML_client_get (client)))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id);
+
+ msg = (struct GNUNET_CADET_LocalAck *) message;
+
+ /* Channel exists? */
+ chid = ntohl (msg->channel_id);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X\n", chid);
+ ch = GML_channel_get (c, chid);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " -- ch %p\n", ch);
+ if (NULL == ch)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %X unknown.\n", chid);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " for client %u.\n", c->id);
+ GNUNET_STATISTICS_update (stats,
+ "# client ack messages on unknown channel",
+ 1, GNUNET_NO);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+
+ /* If client is root, the ACK is going FWD, therefore this is "BCK ACK". */
+ /* If client is dest, the ACK is going BCK, therefore this is "FWD ACK" */
+ fwd = chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV;
+
+ GMCH_handle_local_ack (ch, fwd);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+
+ return;
+}
+
+
+
+/**
+ * Iterator over all peers to send a monitoring client info about each peer.
+ *
+ * @param cls Closure ().
+ * @param peer Peer ID (tunnel remote peer).
+ * @param value Peer info.
+ *
+ * @return #GNUNET_YES, to keep iterating.
+ */
+static int
+get_all_peers_iterator (void *cls,
+ const struct GNUNET_PeerIdentity * peer,
+ void *value)
+{
+ struct GNUNET_SERVER_Client *client = cls;
+ struct CadetPeer *p = value;
+ struct GNUNET_CADET_LocalInfoPeer msg;
+
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
+ msg.destination = *peer;
+ msg.paths = htons (GMP_count_paths (p));
+ msg.tunnel = htons (NULL != GMP_get_tunnel (p));
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "sending info about peer %s\n",
+ GNUNET_i2s (peer));
+
+ GNUNET_SERVER_notification_context_unicast (nc, client,
+ &msg.header, GNUNET_NO);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's INFO PEERS request.
+ *
+ * @param cls Closure (unused).
+ * @param client Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_get_peers (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct CadetClient *c;
+ struct GNUNET_MessageHeader reply;
+
+ /* Sanity check for client registration */
+ if (NULL == (c = GML_client_get (client)))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received get peers request from client %u (%p)\n",
+ c->id, client);
+
+ GMP_iterate_all (get_all_peers_iterator, client);
+ reply.size = htons (sizeof (reply));
+ reply.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
+ GNUNET_SERVER_notification_context_unicast (nc, client, &reply, GNUNET_NO);
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Get peers request from client %u completed\n", c->id);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Iterator over all tunnels to send a monitoring client info about each
tunnel.
+ *
+ * @param cls Closure ().
+ * @param peer Peer ID (tunnel remote peer).
+ * @param value Tunnel info.
+ *
+ * @return #GNUNET_YES, to keep iterating.
+ */
+static int
+get_all_tunnels_iterator (void *cls,
+ const struct GNUNET_PeerIdentity * peer,
+ void *value)
+{
+ struct GNUNET_SERVER_Client *client = cls;
+ struct CadetTunnel3 *t = value;
+ struct GNUNET_CADET_LocalInfoTunnel msg;
+
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
+ msg.destination = *peer;
+ msg.channels = htonl (GMT_count_channels (t));
+ msg.connections = htonl (GMT_count_connections (t));
+ msg.cstate = htons ((uint16_t) GMT_get_cstate (t));
+ msg.estate = htons ((uint16_t) GMT_get_estate (t));
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "sending info about tunnel ->%s\n",
+ GNUNET_i2s (peer));
+
+ GNUNET_SERVER_notification_context_unicast (nc, client,
+ &msg.header, GNUNET_NO);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's INFO TUNNELS request.
+ *
+ * @param cls Closure (unused).
+ * @param client Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_get_tunnels (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct CadetClient *c;
+ struct GNUNET_MessageHeader reply;
+
+ /* Sanity check for client registration */
+ if (NULL == (c = GML_client_get (client)))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received get tunnels request from client %u (%p)\n",
+ c->id, client);
+
+ GMT_iterate_all (get_all_tunnels_iterator, client);
+ reply.size = htons (sizeof (reply));
+ reply.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
+ GNUNET_SERVER_notification_context_unicast (nc, client, &reply, GNUNET_NO);
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Get tunnels request from client %u completed\n", c->id);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+static void
+iter_connection (void *cls, struct CadetConnection *c)
+{
+ struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
+ struct GNUNET_CADET_Hash *h = (struct GNUNET_CADET_Hash *) &msg[1];
+
+ h[msg->connections] = *(GMC_get_id (c));
+ msg->connections++;
+}
+
+static void
+iter_channel (void *cls, struct CadetChannel *ch)
+{
+ struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
+ struct GNUNET_HashCode *h = (struct GNUNET_HashCode *) &msg[1];
+ CADET_ChannelNumber *chn = (CADET_ChannelNumber *) &h[msg->connections];
+
+ chn[msg->channels] = GMCH_get_id (ch);
+ msg->channels++;
+}
+
+
+/**
+ * Handler for client's SHOW_TUNNEL request.
+ *
+ * @param cls Closure (unused).
+ * @param client Identification of the client.
+ * @param message The actual message.
+ */
+void
+handle_show_tunnel (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct GNUNET_CADET_LocalInfo *msg;
+ struct GNUNET_CADET_LocalInfoTunnel *resp;
+ struct CadetClient *c;
+ struct CadetTunnel3 *t;
+ unsigned int ch_n;
+ unsigned int c_n;
+ size_t size;
+
+ /* Sanity check for client registration */
+ if (NULL == (c = GML_client_get (client)))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+
+ msg = (struct GNUNET_CADET_LocalInfo *) message;
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Received tunnel info request from client %u for tunnel %s\n",
+ c->id, GNUNET_i2s_full(&msg->peer));
+
+ t = GMP_get_tunnel (GMP_get (&msg->peer));
+ if (NULL == t)
+ {
+ /* We don't know the tunnel */
+ struct GNUNET_CADET_LocalInfoTunnel warn;
+
+ LOG (GNUNET_ERROR_TYPE_INFO, "Tunnel %s unknown %u\n",
+ GNUNET_i2s_full(&msg->peer), sizeof (warn));
+ warn.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
+ warn.header.size = htons (sizeof (warn));
+ warn.destination = msg->peer;
+ warn.channels = htonl (0);
+ warn.connections = htonl (0);
+ warn.cstate = htons (0);
+ warn.estate = htons (0);
+
+ GNUNET_SERVER_notification_context_unicast (nc, client,
+ &warn.header,
+ GNUNET_NO);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+
+ /* Initialize context */
+ ch_n = GMT_count_channels (t);
+ c_n = GMT_count_connections (t);
+
+ size = sizeof (struct GNUNET_CADET_LocalInfoTunnel);
+ size += c_n * sizeof (struct GNUNET_CADET_Hash);
+ size += ch_n * sizeof (CADET_ChannelNumber);
+
+ resp = GNUNET_malloc (size);
+ resp->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
+ resp->header.size = htons (size);
+ GMT_iterate_connections (t, &iter_connection, resp);
+ GMT_iterate_channels (t, &iter_channel, resp);
+ /* Do not interleave with iterators, iter_channel needs conn in HBO */
+ resp->destination = msg->peer;
+ resp->connections = htonl (resp->connections);
+ resp->channels = htonl (resp->channels);
+ resp->cstate = htons (GMT_get_cstate (t));
+ resp->estate = htons (GMT_get_estate (t));
+ GNUNET_SERVER_notification_context_unicast (nc, c->handle,
+ &resp->header, GNUNET_NO);
+ GNUNET_free (resp);
+
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Show tunnel request from client %u completed. %u conn, %u ch\n",
+ c->id, c_n, ch_n);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Functions to handle messages from clients
+ */
+static struct GNUNET_SERVER_MessageHandler client_handlers[] = {
+ {&handle_new_client, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT, 0},
+ {&handle_channel_create, NULL, GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE,
+ sizeof (struct GNUNET_CADET_ChannelMessage)},
+ {&handle_channel_destroy, NULL, GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY,
+ sizeof (struct GNUNET_CADET_ChannelMessage)},
+ {&handle_data, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA, 0},
+ {&handle_ack, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
+ sizeof (struct GNUNET_CADET_LocalAck)},
+ {&handle_get_peers, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
+ sizeof (struct GNUNET_MessageHeader)},
+ {&handle_get_tunnels, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
+ sizeof (struct GNUNET_MessageHeader)},
+ {&handle_show_tunnel, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
+ sizeof (struct GNUNET_CADET_LocalInfo)},
+ {NULL, NULL, 0, 0}
+};
+
+
+
+/******************************************************************************/
+/******************************** API
***********************************/
+/******************************************************************************/
+
+/**
+ * Initialize server subsystem.
+ *
+ * @param handle Server handle.
+ */
+void
+GML_init (struct GNUNET_SERVER_Handle *handle)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
+ server_handle = handle;
+ GNUNET_SERVER_suspend (server_handle);
+ ports = GNUNET_CONTAINER_multihashmap32_create (32);
+}
+
+
+/**
+ * Install server (service) handlers and start listening to clients.
+ */
+void
+GML_start (void)
+{
+ GNUNET_SERVER_add_handlers (server_handle, client_handlers);
+ GNUNET_SERVER_connect_notify (server_handle, &handle_client_connect, NULL);
+ GNUNET_SERVER_disconnect_notify (server_handle, &handle_client_disconnect,
+ NULL);
+ nc = GNUNET_SERVER_notification_context_create (server_handle, 1);
+
+ clients_head = NULL;
+ clients_tail = NULL;
+ next_client_id = 0;
+ GNUNET_SERVER_resume (server_handle);
+}
+
+
+/**
+ * Shutdown server.
+ */
+void
+GML_shutdown (void)
+{
+ if (nc != NULL)
+ {
+ GNUNET_SERVER_notification_context_destroy (nc);
+ nc = NULL;
+ }
+}
+
+
+/**
+ * Get a channel from a client.
+ *
+ * @param c Client to check.
+ * @param chid Channel ID, must be local (> 0x800...).
+ *
+ * @return non-NULL if channel exists in the clients lists
+ */
+struct CadetChannel *
+GML_channel_get (struct CadetClient *c, CADET_ChannelNumber chid)
+{
+ struct GNUNET_CONTAINER_MultiHashMap32 *map;
+
+ if (0 == (chid & GNUNET_CADET_LOCAL_CHANNEL_ID_CLI))
+ {
+ GNUNET_break_op (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "CHID %X not a local chid\n", chid);
+ return NULL;
+ }
+
+ if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV)
+ map = c->incoming_channels;
+ else if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+ map = c->own_channels;
+ else
+ {
+ GNUNET_break (0);
+ map = NULL;
+ }
+ if (NULL == map)
+ {
+ GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Client %s does no t have a valid map for CHID %X\n",
+ GML_2s (c), chid);
+ return NULL;
+ }
+ return GNUNET_CONTAINER_multihashmap32_get (map, chid);
+}
+
+
+/**
+ * Add a channel to a client
+ *
+ * @param client Client.
+ * @param chid Channel ID.
+ * @param ch Channel.
+ */
+void
+GML_channel_add (struct CadetClient *client,
+ uint32_t chid,
+ struct CadetChannel *ch)
+{
+ if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV)
+ GNUNET_CONTAINER_multihashmap32_put (client->incoming_channels, chid, ch,
+
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
+ else if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+ GNUNET_CONTAINER_multihashmap32_put (client->own_channels, chid, ch,
+
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
+ else
+ GNUNET_break (0);
+}
+
+
+/**
+ * Remove a channel from a client.
+ *
+ * @param client Client.
+ * @param chid Channel ID.
+ * @param ch Channel.
+ */
+void
+GML_channel_remove (struct CadetClient *client,
+ uint32_t chid,
+ struct CadetChannel *ch)
+{
+ if (GNUNET_CADET_LOCAL_CHANNEL_ID_SERV <= chid)
+ GNUNET_break (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap32_remove
(client->incoming_channels,
+ chid, ch));
+ else if (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI <= chid)
+ GNUNET_break (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap32_remove (client->own_channels,
+ chid, ch));
+ else
+ GNUNET_break (0);
+}
+
+
+/**
+ * Get the tunnel's next free local channel ID.
+ *
+ * @param c Client.
+ *
+ * @return LID of a channel free to use.
+ */
+CADET_ChannelNumber
+GML_get_next_chid (struct CadetClient *c)
+{
+ CADET_ChannelNumber chid;
+
+ while (NULL != GML_channel_get (c, c->next_chid))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %u exists...\n", c->next_chid);
+ c->next_chid = (c->next_chid + 1) | GNUNET_CADET_LOCAL_CHANNEL_ID_SERV;
+ }
+ chid = c->next_chid;
+ c->next_chid = (c->next_chid + 1) | GNUNET_CADET_LOCAL_CHANNEL_ID_SERV;
+
+ return chid;
+}
+
+
+/**
+ * Check if client has registered with the service and has not disconnected
+ *
+ * @param client the client to check
+ *
+ * @return non-NULL if client exists in the global DLL
+ */
+struct CadetClient *
+GML_client_get (struct GNUNET_SERVER_Client *client)
+{
+ return GNUNET_SERVER_client_get_user_context (client, struct CadetClient);
+}
+
+/**
+ * Find a client that has opened a port
+ *
+ * @param port Port to check.
+ *
+ * @return non-NULL if a client has the port.
+ */
+struct CadetClient *
+GML_client_get_by_port (uint32_t port)
+{
+ return GNUNET_CONTAINER_multihashmap32_get (ports, port);
+}
+
+
+/**
+ * Deletes a channel from a client (either owner or destination).
+ *
+ * @param c Client whose tunnel to delete.
+ * @param ch Channel which should be deleted.
+ * @param id Channel ID.
+ */
+void
+GML_client_delete_channel (struct CadetClient *c,
+ struct CadetChannel *ch,
+ CADET_ChannelNumber id)
+{
+ int res;
+
+ if (GNUNET_CADET_LOCAL_CHANNEL_ID_SERV <= id)
+ {
+ res = GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels,
+ id, ch);
+ if (GNUNET_YES != res)
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_channel dest KO\n");
+ }
+ else if (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI <= id)
+ {
+ res = GNUNET_CONTAINER_multihashmap32_remove (c->own_channels,
+ id, ch);
+ if (GNUNET_YES != res)
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_tunnel root KO\n");
+ }
+ else
+ {
+ GNUNET_break (0);
+ }
+}
+
+/**
+ * Build a local ACK message and send it to a local client, if needed.
+ *
+ * If the client was already allowed to send data, do nothing.
+ *
+ * @param c Client to whom send the ACK.
+ * @param id Channel ID to use
+ */
+void
+GML_send_ack (struct CadetClient *c, CADET_ChannelNumber id)
+{
+ struct GNUNET_CADET_LocalAck msg;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "send local %s ack on %X towards %p\n",
+ id < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV ? "FWD" : "BCK", id, c);
+
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
+ msg.channel_id = htonl (id);
+ GNUNET_SERVER_notification_context_unicast (nc,
+ c->handle,
+ &msg.header,
+ GNUNET_NO);
+
+}
+
+
+
+/**
+ * Notify the client that a new incoming channel was created.
+ *
+ * @param c Client to notify.
+ * @param id Channel ID.
+ * @param port Channel's destination port.
+ * @param opt Options (bit array).
+ * @param peer Origin peer.
+ */
+void
+GML_send_channel_create (struct CadetClient *c,
+ uint32_t id, uint32_t port, uint32_t opt,
+ const struct GNUNET_PeerIdentity *peer)
+{
+ struct GNUNET_CADET_ChannelMessage msg;
+
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE);
+ msg.channel_id = htonl (id);
+ msg.port = htonl (port);
+ msg.opt = htonl (opt);
+ msg.peer = *peer;
+ GNUNET_SERVER_notification_context_unicast (nc, c->handle,
+ &msg.header, GNUNET_NO);
+}
+
+
+/**
+ * Build a local channel NACK message and send it to a local client.
+ *
+ * @param c Client to whom send the NACK.
+ * @param id Channel ID to use
+ */
+void
+GML_send_channel_nack (struct CadetClient *c, CADET_ChannelNumber id)
+{
+ struct GNUNET_CADET_LocalAck msg;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "send local nack on %X towards %p\n",
+ id, c);
+
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK);
+ msg.channel_id = htonl (id);
+ GNUNET_SERVER_notification_context_unicast (nc,
+ c->handle,
+ &msg.header,
+ GNUNET_NO);
+
+}
+
+/**
+ * Notify a client that a channel is no longer valid.
+ *
+ * @param c Client.
+ * @param id ID of the channel that is destroyed.
+ */
+void
+GML_send_channel_destroy (struct CadetClient *c, uint32_t id)
+{
+ struct GNUNET_CADET_ChannelMessage msg;
+
+ if (NULL == c)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ if (GNUNET_YES == c->shutting_down)
+ return;
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
+ msg.channel_id = htonl (id);
+ msg.port = htonl (0);
+ memset (&msg.peer, 0, sizeof (msg.peer));
+ msg.opt = htonl (0);
+ GNUNET_SERVER_notification_context_unicast (nc, c->handle,
+ &msg.header, GNUNET_NO);
+}
+
+
+/**
+ * Modify the cadet message ID from global to local and send to client.
+ *
+ * @param c Client to send to.
+ * @param msg Message to modify and send.
+ * @param id Channel ID to use (c can be both owner and client).
+ */
+void
+GML_send_data (struct CadetClient *c,
+ const struct GNUNET_CADET_Data *msg,
+ CADET_ChannelNumber id)
+{
+ struct GNUNET_CADET_LocalData *copy;
+ uint16_t size = ntohs (msg->header.size) - sizeof (struct GNUNET_CADET_Data);
+ char cbuf[size + sizeof (struct GNUNET_CADET_LocalData)];
+
+ if (size < sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ if (NULL == c)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ copy = (struct GNUNET_CADET_LocalData *) cbuf;
+ memcpy (©[1], &msg[1], size);
+ copy->header.size = htons (sizeof (struct GNUNET_CADET_LocalData) + size);
+ copy->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
+ copy->id = htonl (id);
+ GNUNET_SERVER_notification_context_unicast (nc, c->handle,
+ ©->header, GNUNET_NO);
+}
+
+
+/**
+ * Get the static string to represent a client.
+ *
+ * @param c Client.
+ *
+ * @return Static string for the client.
+ */
+const char *
+GML_2s (const struct CadetClient *c)
+{
+ static char buf[32];
+
+ sprintf (buf, "%u", c->id);
+ return buf;
+}
Copied: gnunet/src/cadet/gnunet-service-cadet_local.h (from rev 33185,
gnunet/src/mesh/gnunet-service-cadet_local.h)
===================================================================
--- gnunet/src/cadet/gnunet-service-cadet_local.h
(rev 0)
+++ gnunet/src/cadet/gnunet-service-cadet_local.h 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -0,0 +1,226 @@
+/*
+ This file is part of GNUnet.
+ (C) 2013 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_local.h
+ * @brief cadet service; dealing with local clients
+ * @author Bartlomiej Polot
+ *
+ * All functions in this file should use the prefix GML (Gnunet Cadet Local)
+ */
+
+#ifndef GNUNET_SERVICE_CADET_LOCAL_H
+#define GNUNET_SERVICE_CADET_LOCAL_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0 /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+/**
+ * Struct containing information about a client of the service
+ */
+struct CadetClient;
+
+#include "gnunet-service-cadet_channel.h"
+
+/******************************************************************************/
+/******************************** API
***********************************/
+/******************************************************************************/
+
+/**
+ * Initialize server subsystem.
+ *
+ * @param handle Server handle.
+ */
+void
+GML_init (struct GNUNET_SERVER_Handle *handle);
+
+/**
+ * Install server (service) handlers and start listening to clients.
+ */
+void
+GML_start (void);
+
+/**
+ * Shutdown server.
+ */
+void
+GML_shutdown (void);
+
+/**
+ * Get a channel from a client.
+ *
+ * @param c Client to check.
+ * @param chid Channel ID, must be local (> 0x800...).
+ *
+ * @return non-NULL if channel exists in the clients lists
+ */
+struct CadetChannel *
+GML_channel_get (struct CadetClient *c, uint32_t chid);
+
+/**
+ * Add a channel to a client
+ *
+ * @param client Client.
+ * @param chid Channel ID.
+ * @param ch Channel.
+ */
+void
+GML_channel_add (struct CadetClient *client,
+ uint32_t chid,
+ struct CadetChannel *ch);
+
+/**
+ * Remove a channel from a client
+ *
+ * @param client Client.
+ * @param chid Channel ID.
+ * @param ch Channel.
+ */
+void
+GML_channel_remove (struct CadetClient *client,
+ uint32_t chid,
+ struct CadetChannel *ch);
+
+/**
+ * Get the tunnel's next free local channel ID.
+ *
+ * @param c Client.
+ *
+ * @return LID of a channel free to use.
+ */
+CADET_ChannelNumber
+GML_get_next_chid (struct CadetClient *c);
+
+/**
+ * Check if client has registered with the service and has not disconnected
+ *
+ * @param client the client to check
+ *
+ * @return non-NULL if client exists in the global DLL
+ */
+struct CadetClient *
+GML_client_get (struct GNUNET_SERVER_Client *client);
+
+/**
+ * Find a client that has opened a port
+ *
+ * @param port Port to check.
+ *
+ * @return non-NULL if a client has the port.
+ */
+struct CadetClient *
+GML_client_get_by_port (uint32_t port);
+
+/**
+ * Deletes a tunnel from a client (either owner or destination).
+ *
+ * @param c Client whose tunnel to delete.
+ * @param ch Channel which should be deleted.
+ * @param id Channel ID.
+ */
+void
+GML_client_delete_channel (struct CadetClient *c,
+ struct CadetChannel *ch,
+ CADET_ChannelNumber id);
+
+/**
+ * Build a local ACK message and send it to a local client, if needed.
+ *
+ * If the client was already allowed to send data, do nothing.
+ *
+ * @param c Client to whom send the ACK.
+ * @param id Channel ID to use
+ */
+void
+GML_send_ack (struct CadetClient *c, CADET_ChannelNumber id);
+
+/**
+ * Notify the appropriate client that a new incoming channel was created.
+ *
+ * @param c Client to notify.
+ * @param id Channel ID.
+ * @param port Channel's destination port.
+ * @param opt Options (bit array).
+ * @param peer Origin peer.
+ */
+void
+GML_send_channel_create (struct CadetClient *c,
+ uint32_t id, uint32_t port, uint32_t opt,
+ const struct GNUNET_PeerIdentity *peer);
+
+/**
+ * Build a local channel NACK message and send it to a local client.
+ *
+ * @param c Client to whom send the NACK.
+ * @param id Channel ID to use
+ */
+void
+GML_send_channel_nack (struct CadetClient *c, CADET_ChannelNumber id);
+
+/**
+ * Notify a client that a channel is no longer valid.
+ *
+ * @param c Client.
+ * @param id ID of the channel that is destroyed.
+ */
+void
+GML_send_channel_destroy (struct CadetClient *c, uint32_t id);
+
+/**
+ * Modify the cadet message ID from global to local and send to client.
+ *
+ * @param c Client to send to.
+ * @param msg Message to modify and send.
+ * @param id Channel ID to use (c can be both owner and client).
+ */
+void
+GML_send_data (struct CadetClient *c,
+ const struct GNUNET_CADET_Data *msg,
+ CADET_ChannelNumber id);
+
+/**
+ * Get the static string to represent a client.
+ *
+ * @param c Client.
+ *
+ * @return Static string for the client.
+ */
+const char *
+GML_2s (const struct CadetClient *c);
+
+
+#if 0 /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* ifndef GNUNET_CADET_SERVICE_LOCAL_H */
+#endif
+/* end of gnunet-cadet-service_LOCAL.h */
Copied: gnunet/src/cadet/gnunet-service-cadet_peer.c (from rev 33185,
gnunet/src/mesh/gnunet-service-cadet_peer.c)
===================================================================
--- gnunet/src/cadet/gnunet-service-cadet_peer.c
(rev 0)
+++ gnunet/src/cadet/gnunet-service-cadet_peer.c 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -0,0 +1,2219 @@
+/*
+ This file is part of GNUnet.
+ (C) 2013 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+#include "gnunet_transport_service.h"
+#include "gnunet_core_service.h"
+#include "gnunet_statistics_service.h"
+
+#include "cadet_protocol.h"
+
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_dht.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_tunnel.h"
+#include "cadet_path.h"
+
+#define LOG(level, ...) GNUNET_log_from (level,"cadet-p2p",__VA_ARGS__)
+
+/******************************************************************************/
+/******************************** STRUCTS
**********************************/
+/******************************************************************************/
+
+/**
+ * Struct containing info about a queued transmission to this peer
+ */
+struct CadetPeerQueue
+{
+ /**
+ * DLL next
+ */
+ struct CadetPeerQueue *next;
+
+ /**
+ * DLL previous
+ */
+ struct CadetPeerQueue *prev;
+
+ /**
+ * Peer this transmission is directed to.
+ */
+ struct CadetPeer *peer;
+
+ /**
+ * Connection this message belongs to.
+ */
+ struct CadetConnection *c;
+
+ /**
+ * Is FWD in c?
+ */
+ int fwd;
+
+ /**
+ * Pointer to info stucture used as cls.
+ */
+ void *cls;
+
+ /**
+ * Type of message
+ */
+ uint16_t type;
+
+ /**
+ * Type of message
+ */
+ uint16_t payload_type;
+
+ /**
+ * Type of message
+ */
+ uint32_t payload_id;
+
+ /**
+ * Size of the message
+ */
+ size_t size;
+
+ /**
+ * Set when this message starts waiting for CORE.
+ */
+ struct GNUNET_TIME_Absolute start_waiting;
+
+ /**
+ * Function to call on sending.
+ */
+ GMP_sent callback;
+
+ /**
+ * Closure for callback.
+ */
+ void *callback_cls;
+};
+
+/**
+ * Struct containing all information regarding a given peer
+ */
+struct CadetPeer
+{
+ /**
+ * ID of the peer
+ */
+ GNUNET_PEER_Id id;
+
+ /**
+ * Last time we heard from this peer
+ */
+ struct GNUNET_TIME_Absolute last_contact;
+
+ /**
+ * Paths to reach the peer, ordered by ascending hop count
+ */
+ struct CadetPeerPath *path_head;
+
+ /**
+ * Paths to reach the peer, ordered by ascending hop count
+ */
+ struct CadetPeerPath *path_tail;
+
+ /**
+ * Handle to stop the DHT search for paths to this peer
+ */
+ struct GMD_search_handle *search_h;
+
+ /**
+ * Tunnel to this peer, if any.
+ */
+ struct CadetTunnel3 *tunnel;
+
+ /**
+ * Connections that go through this peer, indexed by tid;
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *connections;
+
+ /**
+ * Handle for queued transmissions
+ */
+ struct GNUNET_CORE_TransmitHandle *core_transmit;
+
+ /**
+ * Transmission queue to core DLL head
+ */
+ struct CadetPeerQueue *queue_head;
+
+ /**
+ * Transmission queue to core DLL tail
+ */
+ struct CadetPeerQueue *queue_tail;
+
+ /**
+ * How many messages are in the queue to this peer.
+ */
+ unsigned int queue_n;
+
+ /**
+ * Hello message.
+ */
+ struct GNUNET_HELLO_Message* hello;
+};
+
+
+/******************************************************************************/
+/******************************* GLOBALS
***********************************/
+/******************************************************************************/
+
+/**
+ * Global handle to the statistics service.
+ */
+extern struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Local peer own ID (full value).
+ */
+extern struct GNUNET_PeerIdentity my_full_id;
+
+/**
+ * Local peer own ID (short)
+ */
+extern GNUNET_PEER_Id myid;
+
+/**
+ * Peers known, indexed by PeerIdentity (CadetPeer).
+ */
+static struct GNUNET_CONTAINER_MultiPeerMap *peers;
+
+/**
+ * How many peers do we want to remember?
+ */
+static unsigned long long max_peers;
+
+/**
+ * Percentage of messages that will be dropped (for test purposes only).
+ */
+static unsigned long long drop_percent;
+
+/**
+ * Handle to communicate with core.
+ */
+static struct GNUNET_CORE_Handle *core_handle;
+
+/**
+ * Handle to try to start new connections.
+ */
+static struct GNUNET_TRANSPORT_Handle *transport_handle;
+
+
+/******************************************************************************/
+/***************************** DEBUG
*********************************/
+/******************************************************************************/
+
+static void
+queue_debug (struct CadetPeer *peer)
+{
+ struct CadetPeerQueue *q;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "QQQ Messages queued towards %s\n", GMP_2s
(peer));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "QQQ core tmt rdy: %p\n",
peer->core_transmit);
+
+ for (q = peer->queue_head; NULL != q; q = q->next)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "QQQ - %s %s on %s\n",
+ GM_m2s (q->type), GM_f2s (q->fwd), GMC_2s (q->c));
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "QQQ End queued towards %s\n", GMP_2s (peer));
+}
+
+
+/******************************************************************************/
+/***************************** CORE HELPERS
*********************************/
+/******************************************************************************/
+
+
+/**
+ * Iterator to notify all connections of a broken link. Mark connections
+ * to destroy after all traffic has been sent.
+ *
+ * @param cls Closure (peer disconnected).
+ * @param key Current key code (peer id).
+ * @param value Value in the hash map (connection).
+ *
+ * @return #GNUNET_YES to continue to iterate.
+ */
+static int
+notify_broken (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ struct CadetPeer *peer = cls;
+ struct CadetConnection *c = value;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " notifying %s due to %s\n",
+ GMC_2s (c), GMP_2s (peer));
+ GMC_notify_broken (c, peer);
+
+ return GNUNET_YES;
+}
+
+
+/**
+ * Remove the direct path to the peer.
+ *
+ * @param peer Peer to remove the direct path from.
+ *
+ */
+static struct CadetPeerPath *
+pop_direct_path (struct CadetPeer *peer)
+{
+ struct CadetPeerPath *iter;
+
+ for (iter = peer->path_head; NULL != iter; iter = iter->next)
+ {
+ if (2 <= iter->length)
+ {
+ GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, iter);
+ return iter;
+ }
+ }
+ return NULL;
+}
+
+
+/******************************************************************************/
+/***************************** CORE CALLBACKS
*********************************/
+/******************************************************************************/
+
+/**
+ * Method called whenever a given peer connects.
+ *
+ * @param cls closure
+ * @param peer peer identity this notification is about
+ */
+static void
+core_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ struct CadetPeer *mp;
+ struct CadetPeerPath *path;
+ char own_id[16];
+
+ strncpy (own_id, GNUNET_i2s (&my_full_id), 15);
+ mp = GMP_get (peer);
+ if (myid == mp->id)
+ {
+ LOG (GNUNET_ERROR_TYPE_INFO, "CONNECTED %s (self)\n", own_id);
+ path = path_new (1);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_INFO, "CONNECTED %s <= %s\n",
+ own_id, GNUNET_i2s (peer));
+ path = path_new (2);
+ path->peers[1] = mp->id;
+ GNUNET_PEER_change_rc (mp->id, 1);
+ GNUNET_STATISTICS_update (stats, "# peers", 1, GNUNET_NO);
+ }
+ path->peers[0] = myid;
+ GNUNET_PEER_change_rc (myid, 1);
+ GMP_add_path (mp, path, GNUNET_YES);
+
+ mp->connections = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_YES);
+
+ if (NULL != GMP_get_tunnel (mp) &&
+ 0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, peer))
+ {
+ GMP_connect (mp);
+ }
+
+ return;
+}
+
+
+/**
+ * Method called whenever a peer disconnects.
+ *
+ * @param cls closure
+ * @param peer peer identity this notification is about
+ */
+static void
+core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ struct CadetPeer *p;
+ struct CadetPeerPath *direct_path;
+ char own_id[16];
+
+ strncpy (own_id, GNUNET_i2s (&my_full_id), 15);
+ p = GNUNET_CONTAINER_multipeermap_get (peers, peer);
+ if (NULL == p)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ if (myid == p->id)
+ LOG (GNUNET_ERROR_TYPE_INFO, "DISCONNECTED %s (self)\n", own_id);
+ else
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "DISCONNECTED %s <= %s\n",
+ own_id, GNUNET_i2s (peer));
+ direct_path = pop_direct_path (p);
+ GNUNET_CONTAINER_multihashmap_iterate (p->connections, ¬ify_broken, p);
+ GNUNET_CONTAINER_multihashmap_destroy (p->connections);
+ p->connections = NULL;
+ if (NULL != p->core_transmit)
+ {
+ GNUNET_CORE_notify_transmit_ready_cancel (p->core_transmit);
+ p->core_transmit = NULL;
+ }
+ GNUNET_STATISTICS_update (stats, "# peers", -1, GNUNET_NO);
+
+ path_destroy (direct_path);
+ return;
+}
+
+
+/**
+ * Functions to handle messages from core
+ */
+static struct GNUNET_CORE_MessageHandler core_handlers[] = {
+ {&GMC_handle_create, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, 0},
+ {&GMC_handle_confirm, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK,
+ sizeof (struct GNUNET_CADET_ConnectionACK)},
+ {&GMC_handle_broken, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN,
+ sizeof (struct GNUNET_CADET_ConnectionBroken)},
+ {&GMC_handle_destroy, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY,
+ sizeof (struct GNUNET_CADET_ConnectionDestroy)},
+ {&GMC_handle_ack, GNUNET_MESSAGE_TYPE_CADET_ACK,
+ sizeof (struct GNUNET_CADET_ACK)},
+ {&GMC_handle_poll, GNUNET_MESSAGE_TYPE_CADET_POLL,
+ sizeof (struct GNUNET_CADET_Poll)},
+ {&GMC_handle_encrypted, GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED, 0},
+ {&GMC_handle_kx, GNUNET_MESSAGE_TYPE_CADET_KX, 0},
+ {NULL, 0, 0}
+};
+
+
+/**
+ * To be called on core init/fail.
+ *
+ * @param cls Closure (config)
+ * @param identity the public identity of this peer
+ */
+static void
+core_init (void *cls,
+ const struct GNUNET_PeerIdentity *identity)
+{
+ const struct GNUNET_CONFIGURATION_Handle *c = cls;
+ static int i = 0;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Core init\n");
+ if (0 != memcmp (identity, &my_full_id, sizeof (my_full_id)))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong CORE service\n"));
+ LOG (GNUNET_ERROR_TYPE_ERROR, " core id %s\n", GNUNET_i2s (identity));
+ LOG (GNUNET_ERROR_TYPE_ERROR, " my id %s\n", GNUNET_i2s (&my_full_id));
+ GNUNET_CORE_disconnect (core_handle);
+ core_handle = GNUNET_CORE_connect (c, /* Main configuration */
+ NULL, /* Closure passed to CADET
functions */
+ &core_init, /* Call core_init
once connected */
+ &core_connect, /* Handle connects */
+ &core_disconnect, /* remove peers on
disconnects */
+ NULL, /* Don't notify about all
incoming messages */
+ GNUNET_NO, /* For header only in
notification */
+ NULL, /* Don't notify about all
outbound messages */
+ GNUNET_NO, /* For header-only out
notification */
+ core_handlers); /* Register these
handlers */
+ if (10 < i++)
+ GNUNET_abort();
+ }
+ GML_start ();
+ return;
+}
+
+
+/**
+ * Core callback to write a pre-constructed data packet to core buffer
+ *
+ * @param cls Closure (CadetTransmissionDescriptor with data in "data"
member).
+ * @param size Number of bytes available in buf.
+ * @param buf Where the to write the message.
+ *
+ * @return number of bytes written to buf
+ */
+static size_t
+send_core_data_raw (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_MessageHeader *msg = cls;
+ size_t total_size;
+
+ GNUNET_assert (NULL != msg);
+ total_size = ntohs (msg->size);
+
+ if (total_size > size)
+ {
+ GNUNET_break (0);
+ return 0;
+ }
+ memcpy (buf, msg, total_size);
+ GNUNET_free (cls);
+ return total_size;
+}
+
+
+/**
+ * Function to send a create connection message to a peer.
+ *
+ * @param c Connection to create.
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+static size_t
+send_core_connection_create (struct CadetConnection *c, size_t size, void *buf)
+{
+ struct GNUNET_CADET_ConnectionCreate *msg;
+ struct GNUNET_PeerIdentity *peer_ptr;
+ const struct CadetPeerPath *p = GMC_get_path (c);
+ size_t size_needed;
+ int i;
+
+ if (NULL == p)
+ return 0;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending CONNECTION CREATE...\n");
+ size_needed =
+ sizeof (struct GNUNET_CADET_ConnectionCreate) +
+ p->length * sizeof (struct GNUNET_PeerIdentity);
+
+ if (size < size_needed || NULL == buf)
+ {
+ GNUNET_break (0);
+ return 0;
+ }
+ msg = (struct GNUNET_CADET_ConnectionCreate *) buf;
+ msg->header.size = htons (size_needed);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE);
+ msg->cid = *GMC_get_id (c);
+
+ peer_ptr = (struct GNUNET_PeerIdentity *) &msg[1];
+ for (i = 0; i < p->length; i++)
+ {
+ GNUNET_PEER_resolve (p->peers[i], peer_ptr++);
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "CONNECTION CREATE (%u bytes long) sent!\n",
+ size_needed);
+ return size_needed;
+}
+
+
+/**
+ * Creates a path ack message in buf and frees all unused resources.
+ *
+ * @param c Connection to send an ACK on.
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ *
+ * @return number of bytes written to buf
+ */
+static size_t
+send_core_connection_ack (struct CadetConnection *c, size_t size, void *buf)
+{
+ struct GNUNET_CADET_ConnectionACK *msg = buf;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending CONNECTION ACK...\n");
+ if (sizeof (struct GNUNET_CADET_ConnectionACK) > size)
+ {
+ GNUNET_break (0);
+ return 0;
+ }
+ msg->header.size = htons (sizeof (struct GNUNET_CADET_ConnectionACK));
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK);
+ msg->cid = *GMC_get_id (c);
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "CONNECTION ACK sent!\n");
+ return sizeof (struct GNUNET_CADET_ConnectionACK);
+}
+
+
+/******************************************************************************/
+/******************************** STATIC
***********************************/
+/******************************************************************************/
+
+
+/**
+ * Get priority for a queued message.
+ *
+ * @param q Queued message
+ *
+ * @return CORE priority to use.
+ */
+static enum GNUNET_CORE_Priority
+get_priority (struct CadetPeerQueue *q)
+{
+ enum GNUNET_CORE_Priority low;
+ enum GNUNET_CORE_Priority high;
+
+ if (NULL == q)
+ {
+ GNUNET_break (0);
+ return GNUNET_CORE_PRIO_BACKGROUND;
+ }
+
+ /* Relayed traffic has lower priority, our own traffic has higher */
+ if (NULL == q->c || GNUNET_NO == GMC_is_origin (q->c, q->fwd))
+ {
+ low = GNUNET_CORE_PRIO_BEST_EFFORT;
+ high = GNUNET_CORE_PRIO_URGENT;
+ }
+ else
+ {
+ low = GNUNET_CORE_PRIO_URGENT;
+ high = GNUNET_CORE_PRIO_CRITICAL_CONTROL;
+ }
+
+ /* Bulky payload has lower priority, control traffic has higher. */
+ if (GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED == q->type)
+ return low;
+ else
+ return high;
+}
+
+
+/**
+ * Iterator over tunnel hash map entries to destroy the tunnel during shutdown.
+ *
+ * @param cls closure
+ * @param key current key code
+ * @param value value in the hash map
+ * @return #GNUNET_YES if we should continue to iterate,
+ * #GNUNET_NO if not.
+ */
+static int
+shutdown_tunnel (void *cls,
+ const struct GNUNET_PeerIdentity *key,
+ void *value)
+{
+ struct CadetPeer *p = value;
+ struct CadetTunnel3 *t = p->tunnel;
+
+ if (NULL != t)
+ GMT_destroy (t);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Destroy the peer_info and free any allocated resources linked to it
+ *
+ * @param peer The peer_info to destroy.
+ *
+ * @return GNUNET_OK on success
+ */
+static int
+peer_destroy (struct CadetPeer *peer)
+{
+ struct GNUNET_PeerIdentity id;
+ struct CadetPeerPath *p;
+ struct CadetPeerPath *nextp;
+
+ GNUNET_PEER_resolve (peer->id, &id);
+ GNUNET_PEER_change_rc (peer->id, -1);
+
+ LOG (GNUNET_ERROR_TYPE_WARNING, "destroying peer %s\n", GNUNET_i2s (&id));
+
+ if (GNUNET_YES !=
+ GNUNET_CONTAINER_multipeermap_remove (peers, &id, peer))
+ {
+ GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_WARNING, " not in peermap!!\n");
+ }
+ if (NULL != peer->search_h)
+ {
+ GMD_search_stop (peer->search_h);
+ }
+ p = peer->path_head;
+ while (NULL != p)
+ {
+ nextp = p->next;
+ GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, p);
+ path_destroy (p);
+ p = nextp;
+ }
+ GMT_destroy_empty (peer->tunnel);
+ GNUNET_free (peer);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Returns if peer is used (has a tunnel or is neighbor).
+ *
+ * @param peer Peer to check.
+ *
+ * @return #GNUNET_YES if peer is in use.
+ */
+static int
+peer_is_used (struct CadetPeer *peer)
+{
+ struct CadetPeerPath *p;
+
+ if (NULL != peer->tunnel)
+ return GNUNET_YES;
+
+ for (p = peer->path_head; NULL != p; p = p->next)
+ {
+ if (p->length < 3)
+ return GNUNET_YES;
+ }
+ return GNUNET_NO;
+}
+
+
+/**
+ * Iterator over all the peers to get the oldest timestamp.
+ *
+ * @param cls Closure (unsued).
+ * @param key ID of the peer.
+ * @param value Peer_Info of the peer.
+ */
+static int
+peer_get_oldest (void *cls,
+ const struct GNUNET_PeerIdentity *key,
+ void *value)
+{
+ struct CadetPeer *p = value;
+ struct GNUNET_TIME_Absolute *abs = cls;
+
+ /* Don't count active peers */
+ if (GNUNET_YES == peer_is_used (p))
+ return GNUNET_YES;
+
+ if (abs->abs_value_us < p->last_contact.abs_value_us)
+ abs->abs_value_us = p->last_contact.abs_value_us;
+
+ return GNUNET_YES;
+}
+
+
+/**
+ * Iterator over all the peers to remove the oldest entry.
+ *
+ * @param cls Closure (unsued).
+ * @param key ID of the peer.
+ * @param value Peer_Info of the peer.
+ */
+static int
+peer_timeout (void *cls,
+ const struct GNUNET_PeerIdentity *key,
+ void *value)
+{
+ struct CadetPeer *p = value;
+ struct GNUNET_TIME_Absolute *abs = cls;
+
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "peer %s timeout\n", GNUNET_i2s (key));
+
+ if (p->last_contact.abs_value_us == abs->abs_value_us &&
+ GNUNET_NO == peer_is_used (p))
+ {
+ peer_destroy (p);
+ return GNUNET_NO;
+ }
+ return GNUNET_YES;
+}
+
+
+/**
+ * Delete oldest unused peer.
+ */
+static void
+peer_delete_oldest (void)
+{
+ struct GNUNET_TIME_Absolute abs;
+
+ abs = GNUNET_TIME_UNIT_FOREVER_ABS;
+
+ GNUNET_CONTAINER_multipeermap_iterate (peers,
+ &peer_get_oldest,
+ &abs);
+ GNUNET_CONTAINER_multipeermap_iterate (peers,
+ &peer_timeout,
+ &abs);
+}
+
+
+/**
+ * Choose the best (yet unused) path towards a peer,
+ * considering the tunnel properties.
+ *
+ * @param peer The destination peer.
+ *
+ * @return Best current known path towards the peer, if any.
+ */
+static struct CadetPeerPath *
+peer_get_best_path (const struct CadetPeer *peer)
+{
+ struct CadetPeerPath *best_p;
+ struct CadetPeerPath *p;
+ unsigned int best_cost;
+ unsigned int cost;
+
+ best_cost = UINT_MAX;
+ best_p = NULL;
+ for (p = peer->path_head; NULL != p; p = p->next)
+ {
+ if (GNUNET_NO == path_is_valid (p))
+ continue; /* Don't use invalid paths. */
+ if (GNUNET_YES == GMT_is_path_used (peer->tunnel, p))
+ continue; /* If path is already in use, skip it. */
+
+ if ((cost = GMT_get_path_cost (peer->tunnel, p)) < best_cost)
+ {
+ best_cost = cost;
+ best_p = p;
+ }
+ }
+ return best_p;
+}
+
+
+/**
+ * Is this queue element sendable?
+ *
+ * - All management traffic is always sendable.
+ * - For payload traffic, check the connection flow control.
+ *
+ * @param q Queue element to inspect.
+ *
+ * @return #GNUNET_YES if it is sendable, #GNUNET_NO otherwise.
+ */
+static int
+queue_is_sendable (struct CadetPeerQueue *q)
+{
+ /* Is PID-independent? */
+ switch (q->type)
+ {
+ case GNUNET_MESSAGE_TYPE_CADET_ACK:
+ case GNUNET_MESSAGE_TYPE_CADET_POLL:
+ case GNUNET_MESSAGE_TYPE_CADET_KX:
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK:
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
+ return GNUNET_YES;
+
+ case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
+ break;
+
+ default:
+ GNUNET_break (0);
+ }
+
+ return GMC_is_sendable (q->c, q->fwd);
+}
+
+
+/**
+ * Get first sendable message.
+ *
+ * @param peer The destination peer.
+ *
+ * @return First transmittable message, if any. Otherwise, NULL.
+ */
+static struct CadetPeerQueue *
+peer_get_first_message (const struct CadetPeer *peer)
+{
+ struct CadetPeerQueue *q;
+
+ for (q = peer->queue_head; NULL != q; q = q->next)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking %p towards %s\n", q, GMC_2s
(q->c));
+ if (queue_is_sendable (q))
+ return q;
+ }
+
+ return NULL;
+}
+
+
+/**
+ * Function to process paths received for a new peer addition. The recorded
+ * paths form the initial tunnel, which can be optimized later.
+ * Called on each result obtained for the DHT search.
+ *
+ * @param cls closure
+ * @param path
+ */
+static void
+search_handler (void *cls, const struct CadetPeerPath *path)
+{
+ struct CadetPeer *peer = cls;
+ unsigned int connection_count;
+
+ GMP_add_path_to_all (path, GNUNET_NO);
+
+ /* Count connections */
+ connection_count = GMT_count_connections (peer->tunnel);
+
+ /* If we already have 3 (or more (?!)) connections, it's enough */
+ if (3 <= connection_count)
+ return;
+
+ if (CADET_TUNNEL3_SEARCHING == GMT_get_cstate (peer->tunnel))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ... connect!\n");
+ GMP_connect (peer);
+ }
+ return;
+}
+
+
+
+/**
+ * Core callback to write a queued packet to core buffer
+ *
+ * @param cls Closure (peer info).
+ * @param size Number of bytes available in buf.
+ * @param buf Where the to write the message.
+ *
+ * @return number of bytes written to buf
+ */
+static size_t
+queue_send (void *cls, size_t size, void *buf)
+{
+ struct CadetPeer *peer = cls;
+ struct CadetConnection *c;
+ struct CadetPeerQueue *queue;
+ const struct GNUNET_PeerIdentity *dst_id;
+ size_t data_size;
+ uint32_t pid;
+
+ pid = 0;
+ peer->core_transmit = NULL;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Queue send towards %s (max %u)\n",
+ GMP_2s (peer), size);
+
+ if (NULL == buf || 0 == size)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Buffer size 0.\n");
+ return 0;
+ }
+
+ /* Initialize */
+ queue = peer_get_first_message (peer);
+ if (NULL == queue)
+ {
+ GNUNET_assert (0); /* Core tmt_rdy should've been canceled */
+ return 0;
+ }
+ c = queue->c;
+
+ dst_id = GNUNET_PEER_resolve2 (peer->id);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " on connection %s %s\n",
+ GMC_2s (c), GM_f2s(queue->fwd));
+ /* Check if buffer size is enough for the message */
+ if (queue->size > size)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "not enough room (%u vs %u), reissue\n",
+ queue->size, size);
+ peer->core_transmit =
+ GNUNET_CORE_notify_transmit_ready (core_handle,
+ GNUNET_NO, get_priority (queue),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ dst_id,
+ queue->size,
+ &queue_send,
+ peer);
+ return 0;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " size %u ok\n", queue->size);
+
+ /* Fill buf */
+ switch (queue->type)
+ {
+ case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
+ pid = GMC_get_pid (queue->c, queue->fwd);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " payload ID %u\n", pid);
+ data_size = send_core_data_raw (queue->cls, size, buf);
+ ((struct GNUNET_CADET_Encrypted *) buf)->pid = htonl (pid);
+ break;
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
+ case GNUNET_MESSAGE_TYPE_CADET_KX:
+ case GNUNET_MESSAGE_TYPE_CADET_ACK:
+ case GNUNET_MESSAGE_TYPE_CADET_POLL:
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " raw %s\n", GM_m2s (queue->type));
+ data_size = send_core_data_raw (queue->cls, size, buf);
+ break;
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " path create\n");
+ if (GMC_is_origin (c, GNUNET_YES))
+ data_size = send_core_connection_create (queue->c, size, buf);
+ else
+ data_size = send_core_data_raw (queue->cls, size, buf);
+ break;
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK:
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " path ack\n");
+ if (GMC_is_origin (c, GNUNET_NO) ||
+ GMC_is_origin (c, GNUNET_YES))
+ data_size = send_core_connection_ack (queue->c, size, buf);
+ else
+ data_size = send_core_data_raw (queue->cls, size, buf);
+ break;
+ case GNUNET_MESSAGE_TYPE_CADET_DATA:
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE:
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
+ /* This should be encapsulted */
+ GNUNET_break (0);
+ data_size = 0;
+ break;
+ default:
+ GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_WARNING, " type unknown: %u\n", queue->type);
+ data_size = 0;
+ }
+
+ if (0 < drop_percent &&
+ GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 101) <
drop_percent)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "DD %s on connection %s\n",
+ GM_m2s (queue->type), GMC_2s (c));
+ data_size = 0;
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "snd %s (%s %u) on connection %s (%p) %s (size %u)\n",
+ GM_m2s (queue->type), GM_m2s (queue->payload_type),
+ queue->payload_type, GMC_2s (c), c, GM_f2s (queue->fwd), data_size);
+ }
+
+ /* Free queue, but cls was freed by send_core_* */
+ GMP_queue_destroy (queue, GNUNET_NO, GNUNET_YES, pid);
+
+ /* If more data in queue, send next */
+ queue = peer_get_first_message (peer);
+ if (NULL != queue)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " more data!\n");
+ if (NULL == peer->core_transmit)
+ {
+ peer->core_transmit =
+ GNUNET_CORE_notify_transmit_ready (core_handle,
+ GNUNET_NO, get_priority (queue),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ dst_id,
+ queue->size,
+ &queue_send,
+ peer);
+ queue->start_waiting = GNUNET_TIME_absolute_get ();
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "* tmt rdy called somewhere else\n");
+ }
+// GMC_start_poll (); FIXME needed?
+ }
+ else
+ {
+// GMC_stop_poll(); FIXME needed?
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " return %d\n", data_size);
+ queue_debug (peer);
+ return data_size;
+}
+
+
+/******************************************************************************/
+/******************************** API
***********************************/
+/******************************************************************************/
+
+
+/**
+ * Free a transmission that was already queued with all resources
+ * associated to the request.
+ *
+ * @param queue Queue handler to cancel.
+ * @param clear_cls Is it necessary to free associated cls?
+ * @param sent Was it really sent? (Could have been canceled)
+ * @param pid PID, if relevant (was sent and was a payload message).
+ */
+void
+GMP_queue_destroy (struct CadetPeerQueue *queue, int clear_cls,
+ int sent, uint32_t pid)
+{
+ struct CadetPeer *peer;
+
+ peer = queue->peer;
+
+ if (GNUNET_YES == clear_cls)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "queue destroy type %s\n",
+ GM_m2s (queue->type));
+ switch (queue->type)
+ {
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
+ LOG (GNUNET_ERROR_TYPE_INFO, "destroying a DESTROY message\n");
+ /* fall through */
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK:
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
+ case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE:
+ case GNUNET_MESSAGE_TYPE_CADET_KX:
+ case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
+ case GNUNET_MESSAGE_TYPE_CADET_ACK:
+ case GNUNET_MESSAGE_TYPE_CADET_POLL:
+ GNUNET_free_non_null (queue->cls);
+ break;
+
+ default:
+ GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_ERROR, " type %s unknown!\n",
+ GM_m2s (queue->type));
+ }
+ }
+ GNUNET_CONTAINER_DLL_remove (peer->queue_head, peer->queue_tail, queue);
+
+ if (queue->type != GNUNET_MESSAGE_TYPE_CADET_ACK &&
+ queue->type != GNUNET_MESSAGE_TYPE_CADET_POLL)
+ {
+ peer->queue_n--;
+ }
+
+ if (NULL != queue->callback)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " calling callback\n");
+ queue->callback (queue->callback_cls,
+ queue->c, sent, queue->type, pid,
+ queue->fwd, queue->size,
+ GNUNET_TIME_absolute_get_duration (queue->start_waiting));
+ }
+
+ if (NULL == peer_get_first_message (peer) && NULL != peer->core_transmit)
+ {
+ GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit);
+ peer->core_transmit = NULL;
+ }
+
+ GNUNET_free (queue);
+}
+
+
+/**
+ * @brief Queue and pass message to core when possible.
+ *
+ * @param peer Peer towards which to queue the message.
+ * @param cls Closure (@c type dependant). It will be used by queue_send to
+ * build the message to be sent if not already prebuilt.
+ * @param type Type of the message, 0 for a raw message.
+ * @param size Size of the message.
+ * @param c Connection this message belongs to (can be NULL).
+ * @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!)
+ * @param cont Continuation to be called once CORE has taken the message.
+ * @param cont_cls Closure for @c cont.
+ *
+ * @return Handle to cancel the message before it is sent. Once cont is called
+ * message has been sent and therefore the handle is no longer valid.
+ */
+struct CadetPeerQueue *
+GMP_queue_add (struct CadetPeer *peer, void *cls, uint16_t type,
+ uint16_t payload_type, uint32_t payload_id, size_t size,
+ struct CadetConnection *c, int fwd,
+ GMP_sent cont, void *cont_cls)
+{
+ struct CadetPeerQueue *queue;
+ int priority;
+ int call_core;
+
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "que %s (%s %u) on connection %s (%p) %s towards %s (size %u)\n",
+ GM_m2s (type), GM_m2s (payload_type), payload_id,
+ GMC_2s (c), c, GM_f2s (fwd), GMP_2s (peer), size);
+
+ if (NULL == peer->connections)
+ {
+ /* We are not connected to this peer, ignore request. */
+ LOG (GNUNET_ERROR_TYPE_WARNING, "%s not a neighbor\n", GMP_2s (peer));
+ GNUNET_STATISTICS_update (stats, "# messages dropped due to wrong hop", 1,
+ GNUNET_NO);
+ return NULL;
+ }
+
+ priority = 0;
+
+ if (GNUNET_MESSAGE_TYPE_CADET_POLL == type ||
+ GNUNET_MESSAGE_TYPE_CADET_ACK == type)
+ {
+ priority = 100;
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "priority %d\n", priority);
+
+ call_core = NULL == c ? GNUNET_YES : GMC_is_sendable (c, fwd);
+ queue = GNUNET_new (struct CadetPeerQueue);
+ queue->cls = cls;
+ queue->type = type;
+ queue->payload_type = payload_type;
+ queue->payload_id = payload_id;
+ queue->size = size;
+ queue->peer = peer;
+ queue->c = c;
+ queue->fwd = fwd;
+ queue->callback = cont;
+ queue->callback_cls = cont_cls;
+ if (100 > priority)
+ {
+ GNUNET_CONTAINER_DLL_insert_tail (peer->queue_head, peer->queue_tail,
queue);
+ peer->queue_n++;
+ }
+ else
+ {
+ GNUNET_CONTAINER_DLL_insert (peer->queue_head, peer->queue_tail, queue);
+ call_core = GNUNET_YES;
+ }
+
+ if (NULL == peer->core_transmit && GNUNET_YES == call_core)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "calling core tmt rdy towards %s for %u bytes\n",
+ GMP_2s (peer), size);
+ peer->core_transmit =
+ GNUNET_CORE_notify_transmit_ready (core_handle,
+ GNUNET_NO, get_priority (queue),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_PEER_resolve2 (peer->id),
+ size,
+ &queue_send,
+ peer);
+ queue->start_waiting = GNUNET_TIME_absolute_get ();
+ }
+ else if (GNUNET_NO == call_core)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "core tmt rdy towards %s not needed\n",
+ GMP_2s (peer));
+
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "core tmt rdy towards %s already called\n",
+ GMP_2s (peer));
+
+ }
+ queue_debug (peer);
+ return queue;
+}
+
+
+/**
+ * Cancel all queued messages to a peer that belong to a certain connection.
+ *
+ * @param peer Peer towards whom to cancel.
+ * @param c Connection whose queued messages to cancel. Might be destroyed by
+ * the sent continuation call.
+ */
+void
+GMP_queue_cancel (struct CadetPeer *peer, struct CadetConnection *c)
+{
+ struct CadetPeerQueue *q;
+ struct CadetPeerQueue *next;
+ struct CadetPeerQueue *prev;
+
+ for (q = peer->queue_head; NULL != q; q = next)
+ {
+ prev = q->prev;
+ if (q->c == c)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "GMP queue cancel %s\n", GM_m2s (q->type));
+ if (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY != q->type)
+ {
+ q->c = NULL;
+ }
+ else
+ {
+ GMP_queue_destroy (q, GNUNET_YES, GNUNET_NO, 0);
+ }
+
+ /* Get next from prev, q->next might be already freed:
+ * queue destroy -> callback -> GMC_destroy -> cancel_queues -> here
+ */
+ if (NULL == prev)
+ next = peer->queue_head;
+ else
+ next = prev->next;
+ }
+ else
+ {
+ next = q->next;
+ }
+ }
+ if (NULL == peer->queue_head)
+ {
+ if (NULL != peer->core_transmit)
+ {
+ GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit);
+ peer->core_transmit = NULL;
+ }
+ }
+}
+
+
+/**
+ * Get the first transmittable message for a connection.
+ *
+ * @param peer Neighboring peer.
+ * @param c Connection.
+ *
+ * @return First transmittable message.
+ */
+static struct CadetPeerQueue *
+connection_get_first_message (struct CadetPeer *peer, struct CadetConnection
*c)
+{
+ struct CadetPeerQueue *q;
+
+ for (q = peer->queue_head; NULL != q; q = q->next)
+ {
+ if (q->c != c)
+ continue;
+ if (queue_is_sendable (q))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " sendable!!\n");
+ return q;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " not sendable\n");
+ }
+
+ return NULL;
+}
+
+
+/**
+ * Get the first message for a connection and unqueue it.
+ *
+ * @param peer Neighboring peer.
+ * @param c Connection.
+ *
+ * @return First message for this connection.
+ */
+struct GNUNET_MessageHeader *
+GMP_connection_pop (struct CadetPeer *peer, struct CadetConnection *c)
+{
+ struct CadetPeerQueue *q;
+ struct CadetPeerQueue *next;
+ struct GNUNET_MessageHeader *msg;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection pop on %s\n", GMC_2s (c));
+ for (q = peer->queue_head; NULL != q; q = next)
+ {
+ next = q->next;
+ if (q->c != c)
+ continue;
+ switch (q->type)
+ {
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK:
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
+ case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
+ case GNUNET_MESSAGE_TYPE_CADET_ACK:
+ case GNUNET_MESSAGE_TYPE_CADET_POLL:
+ GMP_queue_destroy (q, GNUNET_YES, GNUNET_NO, 0);
+ continue;
+
+ case GNUNET_MESSAGE_TYPE_CADET_KX:
+ case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
+ msg = (struct GNUNET_MessageHeader *) q->cls;
+ GMP_queue_destroy (q, GNUNET_NO, GNUNET_NO, 0);
+ return msg;
+
+ default:
+ GNUNET_break (0);
+ }
+ }
+
+ return NULL;
+}
+
+
+void
+GMP_queue_unlock (struct CadetPeer *peer, struct CadetConnection *c)
+{
+ struct CadetPeerQueue *q;
+ size_t size;
+
+ if (NULL != peer->core_transmit)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " already unlocked!\n");
+ return; /* Already unlocked */
+ }
+
+ q = connection_get_first_message (peer, c);
+ if (NULL == q)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " queue empty!\n");
+ return; /* Nothing to transmit */
+ }
+
+ size = q->size;
+ peer->core_transmit =
+ GNUNET_CORE_notify_transmit_ready (core_handle,
+ GNUNET_NO, get_priority (q),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_PEER_resolve2 (peer->id),
+ size,
+ &queue_send,
+ peer);
+}
+
+
+/**
+ * Initialize the peer subsystem.
+ *
+ * @param c Configuration.
+ */
+void
+GMP_init (const struct GNUNET_CONFIGURATION_Handle *c)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
+ peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_PEERS",
+ &max_peers))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
+ "CADET", "MAX_PEERS", "USING DEFAULT");
+ max_peers = 1000;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (c, "CADET", "DROP_PERCENT",
+ &drop_percent))
+ {
+ drop_percent = 0;
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
"**************************************\n");
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n");
+ LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n");
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n");
+ LOG (GNUNET_ERROR_TYPE_WARNING,
"**************************************\n");
+ }
+
+ core_handle = GNUNET_CORE_connect (c, /* Main configuration */
+ NULL, /* Closure passed to CADET
functions */
+ &core_init, /* Call core_init once
connected */
+ &core_connect, /* Handle connects */
+ &core_disconnect, /* remove peers on
disconnects */
+ NULL, /* Don't notify about all
incoming messages */
+ GNUNET_NO, /* For header only in
notification */
+ NULL, /* Don't notify about all
outbound messages */
+ GNUNET_NO, /* For header-only out
notification */
+ core_handlers); /* Register these
handlers */
+ if (GNUNET_YES !=
+ GNUNET_CONFIGURATION_get_value_yesno (c, "CADET", "DISABLE_TRY_CONNECT"))
+ {
+ transport_handle = GNUNET_TRANSPORT_connect (c, &my_full_id, NULL, /* cls
*/
+ /* Notify callbacks */
+ NULL, NULL, NULL);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
"**************************************\n");
+ LOG (GNUNET_ERROR_TYPE_WARNING, "* DISABLE TRYING CONNECT in config
*\n");
+ LOG (GNUNET_ERROR_TYPE_WARNING, "* Use this only for test purposes.
*\n");
+ LOG (GNUNET_ERROR_TYPE_WARNING,
"**************************************\n");
+ transport_handle = NULL;
+ }
+
+
+
+ if (NULL == core_handle)
+ {
+ GNUNET_break (0);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+}
+
+/**
+ * Shut down the peer subsystem.
+ */
+void
+GMP_shutdown (void)
+{
+ GNUNET_CONTAINER_multipeermap_iterate (peers, &shutdown_tunnel, NULL);
+
+ if (core_handle != NULL)
+ {
+ GNUNET_CORE_disconnect (core_handle);
+ core_handle = NULL;
+ }
+ if (transport_handle != NULL)
+ {
+ GNUNET_TRANSPORT_disconnect (transport_handle);
+ transport_handle = NULL;
+ }
+ GNUNET_PEER_change_rc (myid, -1);
+}
+
+/**
+ * Retrieve the CadetPeer stucture associated with the peer, create one
+ * and insert it in the appropriate structures if the peer is not known yet.
+ *
+ * @param peer_id Full identity of the peer.
+ *
+ * @return Existing or newly created peer structure.
+ */
+struct CadetPeer *
+GMP_get (const struct GNUNET_PeerIdentity *peer_id)
+{
+ struct CadetPeer *peer;
+
+ peer = GNUNET_CONTAINER_multipeermap_get (peers, peer_id);
+ if (NULL == peer)
+ {
+ peer = GNUNET_new (struct CadetPeer);
+ if (GNUNET_CONTAINER_multipeermap_size (peers) > max_peers)
+ {
+ peer_delete_oldest ();
+ }
+ GNUNET_CONTAINER_multipeermap_put (peers, peer_id, peer,
+
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+ peer->id = GNUNET_PEER_intern (peer_id);
+ }
+ peer->last_contact = GNUNET_TIME_absolute_get();
+
+ return peer;
+}
+
+
+/**
+ * Retrieve the CadetPeer stucture associated with the peer, create one
+ * and insert it in the appropriate structures if the peer is not known yet.
+ *
+ * @param peer Short identity of the peer.
+ *
+ * @return Existing or newly created peer structure.
+ */
+struct CadetPeer *
+GMP_get_short (const GNUNET_PEER_Id peer)
+{
+ return GMP_get (GNUNET_PEER_resolve2 (peer));
+}
+
+
+/**
+ * Try to connect to a peer on transport level.
+ *
+ * @param cls Closure (peer).
+ * @param tc TaskContext.
+ */
+static void
+try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct CadetPeer *peer = cls;
+
+ if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+ return;
+
+ GNUNET_TRANSPORT_try_connect (transport_handle,
+ GNUNET_PEER_resolve2 (peer->id), NULL, NULL);
+}
+
+
+/**
+ * Try to establish a new connection to this peer (in its tunnel).
+ * If the peer doesn't have any path to it yet, try to get one.
+ * If the peer already has some path, send a CREATE CONNECTION towards it.
+ *
+ * @param peer Peer to connect to.
+ */
+void
+GMP_connect (struct CadetPeer *peer)
+{
+ struct CadetTunnel3 *t;
+ struct CadetPeerPath *p;
+ struct CadetConnection *c;
+ int rerun_search;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "peer_connect towards %s\n", GMP_2s (peer));
+
+ /* If we have a current hello, try to connect using it. */
+ GMP_try_connect (peer);
+
+ t = peer->tunnel;
+ c = NULL;
+ rerun_search = GNUNET_NO;
+
+ if (NULL != peer->path_head)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " some path exists\n");
+ p = peer_get_best_path (peer);
+ if (NULL != p)
+ {
+ char *s;
+
+ s = path_2s (p);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " path to use: %s\n", s);
+ GNUNET_free (s);
+
+ c = GMT_use_path (t, p);
+ if (NULL == c)
+ {
+ /* This case can happen when the path includes a first hop that is
+ * not yet known to be connected.
+ *
+ * This happens quite often during testing when running cadet
+ * under valgrind: core connect notifications come very late and the
+ * DHT result has already come and created a valid path.
+ * In this case, the peer->connections hashmap will be NULL and
+ * tunnel_use_path will not be able to create a connection from that
+ * path.
+ *
+ * Re-running the DHT GET should give core time to callback.
+ *
+ * GMT_use_path -> GMC_new -> register_neighbors takes care of
+ * updating statistics about this issue.
+ */
+ rerun_search = GNUNET_YES;
+ }
+ else
+ {
+ GMC_send_create (c);
+ return;
+ }
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " but is NULL, all paths are in use\n");
+ }
+ }
+
+ if (NULL != peer->search_h && GNUNET_YES == rerun_search)
+ {
+ GMD_search_stop (peer->search_h);
+ peer->search_h = NULL;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " Stopping DHT GET for peer %s\n",
+ GMP_2s (peer));
+ }
+
+ if (NULL == peer->search_h)
+ {
+ const struct GNUNET_PeerIdentity *id;
+
+ id = GNUNET_PEER_resolve2 (peer->id);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " Starting DHT GET for peer %s\n", GMP_2s (peer));
+ peer->search_h = GMD_search (id, &search_handler, peer);
+ if (CADET_TUNNEL3_NEW == GMT_get_cstate (t))
+ GMT_change_cstate (t, CADET_TUNNEL3_SEARCHING);
+ }
+}
+
+
+/**
+ * Chech whether there is a direct (core level) connection to peer.
+ *
+ * @param peer Peer to check.
+ *
+ * @return #GNUNET_YES if there is a direct connection.
+ */
+int
+GMP_is_neighbor (const struct CadetPeer *peer)
+{
+ struct CadetPeerPath *path;
+
+ if (NULL == peer->connections)
+ return GNUNET_NO;
+
+ for (path = peer->path_head; NULL != path; path = path->next)
+ {
+ if (3 > path->length)
+ return GNUNET_YES;
+ }
+
+ /* Is not a neighbor but connections is not NULL, probably disconnecting */
+ return GNUNET_NO;
+}
+
+
+/**
+ * Create and initialize a new tunnel towards a peer, in case it has none.
+ * In case the peer already has a tunnel, nothing is done.
+ *
+ * Does not generate any traffic, just creates the local data structures.
+ *
+ * @param peer Peer towards which to create the tunnel.
+ */
+void
+GMP_add_tunnel (struct CadetPeer *peer)
+{
+ if (NULL != peer->tunnel)
+ return;
+ peer->tunnel = GMT_new (peer);
+}
+
+
+/**
+ * Add a connection to a neighboring peer.
+ *
+ * Store that the peer is the first hop of the connection in one
+ * direction and that on peer disconnect the connection must be
+ * notified and destroyed, for it will no longer be valid.
+ *
+ * @param peer Peer to add connection to.
+ * @param c Connection to add.
+ *
+ * @return GNUNET_OK on success.
+ */
+int
+GMP_add_connection (struct CadetPeer *peer,
+ struct CadetConnection *c)
+{
+ int result;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "adding connection %s\n", GMC_2s (c));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "to peer %s\n", GMP_2s (peer));
+
+ if (NULL == peer->connections)
+ {
+ GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %s is not a neighbor!\n",
+ GMP_2s (peer));
+ return GNUNET_SYSERR;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "peer %s ok, has %u connections.\n",
+ GMP_2s (peer), GNUNET_CONTAINER_multihashmap_size (peer->connections));
+ result = GNUNET_CONTAINER_multihashmap_put (peer->connections,
+ GMC_get_h (c),
+ c,
+
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " now has %u connections.\n",
+ GNUNET_CONTAINER_multihashmap_size (peer->connections));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "result %u\n", result);
+
+ return result;
+}
+
+
+/**
+ * Add the path to the peer and update the path used to reach it in case this
+ * is the shortest.
+ *
+ * @param peer Destination peer to add the path to.
+ * @param path New path to add. Last peer must be the peer in arg 1.
+ * Path will be either used of freed if already known.
+ * @param trusted Do we trust that this path is real?
+ *
+ * @return path if path was taken, pointer to existing duplicate if exists
+ * NULL on error.
+ */
+struct CadetPeerPath *
+GMP_add_path (struct CadetPeer *peer, struct CadetPeerPath *path,
+ int trusted)
+{
+ struct CadetPeerPath *aux;
+ unsigned int l;
+ unsigned int l2;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "adding path [%u] to peer %s\n",
+ path->length, GMP_2s (peer));
+
+ if ((NULL == peer) || (NULL == path))
+ {
+ GNUNET_break (0);
+ path_destroy (path);
+ return NULL;
+ }
+ if (path->peers[path->length - 1] != peer->id)
+ {
+ GNUNET_break (0);
+ path_destroy (path);
+ return NULL;
+ }
+
+ for (l = 1; l < path->length; l++)
+ {
+ if (path->peers[l] == myid)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " shortening path by %u\n", l);
+ for (l2 = 0; l2 < path->length - l; l2++)
+ {
+ path->peers[l2] = path->peers[l + l2];
+ }
+ path->length -= l;
+ l = 1;
+ path->peers = GNUNET_realloc (path->peers,
+ path->length * sizeof (GNUNET_PEER_Id));
+ }
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " final length: %u\n", path->length);
+
+ if (2 >= path->length && GNUNET_NO == trusted)
+ {
+ /* Only allow CORE to tell us about direct paths */
+ path_destroy (path);
+ return NULL;
+ }
+
+ l = path_get_length (path);
+ if (0 == l)
+ {
+ path_destroy (path);
+ return NULL;
+ }
+
+ GNUNET_assert (peer->id == path->peers[path->length - 1]);
+ for (aux = peer->path_head; aux != NULL; aux = aux->next)
+ {
+ l2 = path_get_length (aux);
+ if (l2 > l)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " added\n");
+ GNUNET_CONTAINER_DLL_insert_before (peer->path_head,
+ peer->path_tail, aux, path);
+ if (NULL != peer->tunnel && 3 < GMT_count_connections (peer->tunnel))
+ {
+ GMP_connect (peer);
+ }
+ return path;
+ }
+ else
+ {
+ if (l2 == l && memcmp (path->peers, aux->peers, l) == 0)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " already known\n");
+ path_destroy (path);
+ return aux;
+ }
+ }
+ }
+ GNUNET_CONTAINER_DLL_insert_tail (peer->path_head, peer->path_tail,
+ path);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " added last\n");
+ if (NULL != peer->tunnel && 3 < GMT_count_connections (peer->tunnel))
+ {
+ GMP_connect (peer);
+ }
+ return path;
+}
+
+
+/**
+ * Add the path to the origin peer and update the path used to reach it in case
+ * this is the shortest.
+ * The path is given in peer_info -> destination, therefore we turn the path
+ * upside down first.
+ *
+ * @param peer Peer to add the path to, being the origin of the path.
+ * @param path New path to add after being inversed.
+ * Path will be either used or freed.
+ * @param trusted Do we trust that this path is real?
+ *
+ * @return path if path was taken, pointer to existing duplicate if exists
+ * NULL on error.
+ */
+struct CadetPeerPath *
+GMP_add_path_to_origin (struct CadetPeer *peer,
+ struct CadetPeerPath *path,
+ int trusted)
+{
+ if (NULL == path)
+ return NULL;
+ path_invert (path);
+ return GMP_add_path (peer, path, trusted);
+}
+
+
+/**
+ * Adds a path to the info of all the peers in the path
+ *
+ * @param p Path to process.
+ * @param confirmed Whether we know if the path works or not.
+ */
+void
+GMP_add_path_to_all (const struct CadetPeerPath *p, int confirmed)
+{
+ unsigned int i;
+
+ /* TODO: invert and add */
+ for (i = 0; i < p->length && p->peers[i] != myid; i++) /* skip'em */ ;
+ for (i++; i < p->length; i++)
+ {
+ struct CadetPeer *aux;
+ struct CadetPeerPath *copy;
+
+ aux = GMP_get_short (p->peers[i]);
+ copy = path_duplicate (p);
+ copy->length = i + 1;
+ GMP_add_path (aux, copy, p->length < 3 ? GNUNET_NO : confirmed);
+ }
+}
+
+
+/**
+ * Remove any path to the peer that has the extact same peers as the one given.
+ *
+ * @param peer Peer to remove the path from.
+ * @param path Path to remove. Is always destroyed .
+ */
+void
+GMP_remove_path (struct CadetPeer *peer, struct CadetPeerPath *path)
+{
+ struct CadetPeerPath *iter;
+ struct CadetPeerPath *next;
+
+ GNUNET_assert (myid == path->peers[0]);
+ GNUNET_assert (peer->id == path->peers[path->length - 1]);
+
+ for (iter = peer->path_head; NULL != iter; iter = next)
+ {
+ next = iter->next;
+ if (0 == memcmp (path->peers, iter->peers,
+ sizeof (GNUNET_PEER_Id) * path->length))
+ {
+ GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, iter);
+ if (iter != path)
+ path_destroy (iter);
+ }
+ }
+ path_destroy (path);
+}
+
+
+/**
+ * Remove a connection from a neighboring peer.
+ *
+ * @param peer Peer to remove connection from.
+ * @param c Connection to remove.
+ *
+ * @return GNUNET_OK on success.
+ */
+int
+GMP_remove_connection (struct CadetPeer *peer,
+ const struct CadetConnection *c)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "removing connection %s\n", GMC_2s (c));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "from peer %s\n", GMP_2s (peer));
+
+ if (NULL == peer || NULL == peer->connections)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %s is not a neighbor!\n",
+ GMP_2s (peer));
+ return GNUNET_SYSERR;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "peer %s ok, has %u connections.\n",
+ GMP_2s (peer), GNUNET_CONTAINER_multihashmap_size (peer->connections));
+
+ return GNUNET_CONTAINER_multihashmap_remove (peer->connections,
+ GMC_get_h (c),
+ c);
+}
+
+/**
+ * Start the DHT search for new paths towards the peer: we don't have
+ * enough good connections.
+ *
+ * @param peer Destination peer.
+ */
+void
+GMP_start_search (struct CadetPeer *peer)
+{
+ if (NULL != peer->search_h)
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ peer->search_h = GMD_search (GMP_get_id (peer), &search_handler, peer);
+}
+
+
+/**
+ * Stop the DHT search for new paths towards the peer: we already have
+ * enough good connections.
+ *
+ * @param peer Destination peer.
+ */
+void
+GMP_stop_search (struct CadetPeer *peer)
+{
+ if (NULL == peer->search_h)
+ {
+ return;
+ }
+
+ GMD_search_stop (peer->search_h);
+ peer->search_h = NULL;
+}
+
+
+/**
+ * Get the Full ID of a peer.
+ *
+ * @param peer Peer to get from.
+ *
+ * @return Full ID of peer.
+ */
+const struct GNUNET_PeerIdentity *
+GMP_get_id (const struct CadetPeer *peer)
+{
+ return GNUNET_PEER_resolve2 (peer->id);
+}
+
+
+/**
+ * Get the Short ID of a peer.
+ *
+ * @param peer Peer to get from.
+ *
+ * @return Short ID of peer.
+ */
+GNUNET_PEER_Id
+GMP_get_short_id (const struct CadetPeer *peer)
+{
+ return peer->id;
+}
+
+
+/**
+ * Set tunnel.
+ *
+ * @param peer Peer.
+ * @param t Tunnel.
+ */
+void
+GMP_set_tunnel (struct CadetPeer *peer, struct CadetTunnel3 *t)
+{
+ peer->tunnel = t;
+ if (NULL == t && NULL != peer->search_h)
+ {
+ GMP_stop_search (peer);
+ }
+}
+
+
+/**
+ * Get the tunnel towards a peer.
+ *
+ * @param peer Peer to get from.
+ *
+ * @return Tunnel towards peer.
+ */
+struct CadetTunnel3 *
+GMP_get_tunnel (const struct CadetPeer *peer)
+{
+ return peer->tunnel;
+}
+
+
+/**
+ * Set the hello message.
+ *
+ * @param peer Peer whose message to set.
+ * @param hello Hello message.
+ */
+void
+GMP_set_hello (struct CadetPeer *peer, const struct GNUNET_HELLO_Message
*hello)
+{
+ struct GNUNET_HELLO_Message *old;
+ size_t size;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "set hello for %s\n", GMP_2s (peer));
+ if (NULL == hello)
+ return;
+
+ old = GMP_get_hello (peer);
+ if (NULL == old)
+ {
+ size = GNUNET_HELLO_size (hello);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " new (%u bytes)\n", size);
+ peer->hello = GNUNET_malloc (size);
+ memcpy (peer->hello, hello, size);
+ }
+ else
+ {
+ peer->hello = GNUNET_HELLO_merge (old, hello);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " merge into %p (%u bytes)\n",
+ peer->hello, GNUNET_HELLO_size (hello));
+ GNUNET_free (old);
+ }
+}
+
+
+/**
+ * Get the hello message.
+ *
+ * @param peer Peer whose message to get.
+ *
+ * @return Hello message.
+ */
+struct GNUNET_HELLO_Message *
+GMP_get_hello (struct CadetPeer *peer)
+{
+ struct GNUNET_TIME_Absolute expiration;
+ struct GNUNET_TIME_Relative remaining;
+
+ if (NULL == peer->hello)
+ return NULL;
+
+ expiration = GNUNET_HELLO_get_last_expiration (peer->hello);
+ remaining = GNUNET_TIME_absolute_get_remaining (expiration);
+ if (0 == remaining.rel_value_us)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " get - hello expired on %s\n",
+ GNUNET_STRINGS_absolute_time_to_string (expiration));
+ GNUNET_free (peer->hello);
+ peer->hello = NULL;
+ }
+ return peer->hello;
+}
+
+
+/**
+ * Try to connect to a peer on TRANSPORT level.
+ *
+ * @param peer Peer to whom to connect.
+ */
+void
+GMP_try_connect (struct CadetPeer *peer)
+{
+ struct GNUNET_HELLO_Message *hello;
+ struct GNUNET_MessageHeader *mh;
+
+ if (NULL == transport_handle)
+ return;
+
+ hello = GMP_get_hello (peer);
+ if (NULL == hello)
+ return;
+
+ mh = GNUNET_HELLO_get_header (hello);
+ GNUNET_TRANSPORT_offer_hello (transport_handle, mh, try_connect, peer);
+}
+
+
+/**
+ * Notify a peer that a link between two other peers is broken. If any path
+ * used that link, eliminate it.
+ *
+ * @param peer Peer affected by the change.
+ * @param peer1 Peer whose link is broken.
+ * @param peer2 Peer whose link is broken.
+ */
+void
+GMP_notify_broken_link (struct CadetPeer *peer,
+ struct GNUNET_PeerIdentity *peer1,
+ struct GNUNET_PeerIdentity *peer2)
+{
+ struct CadetPeerPath *iter;
+ struct CadetPeerPath *next;
+ unsigned int i;
+ GNUNET_PEER_Id p1;
+ GNUNET_PEER_Id p2;
+
+ p1 = GNUNET_PEER_search (peer1);
+ p2 = GNUNET_PEER_search (peer2);
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Link %u-%u broken\n", p1, p2);
+ if (0 == p1 || 0 == p2)
+ {
+ /* We don't even know them */
+ return;
+ }
+
+ for (iter = peer->path_head; NULL != iter; iter = next)
+ {
+ next = iter->next;
+ for (i = 0; i < iter->length - 1; i++)
+ {
+ if ((iter->peers[i] == p1 && iter->peers[i + 1] == p2)
+ || (iter->peers[i] == p2 && iter->peers[i + 1] == p1))
+ {
+ char *s;
+
+ s = path_2s (iter);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " - invalidating %s\n", s);
+ GNUNET_free (s);
+
+ path_invalidate (iter);
+ }
+ }
+ }
+}
+
+
+/**
+ * Count the number of known paths toward the peer.
+ *
+ * @param peer Peer to get path info.
+ *
+ * @return Number of known paths.
+ */
+unsigned int
+GMP_count_paths (const struct CadetPeer *peer)
+{
+ struct CadetPeerPath *iter;
+ unsigned int i;
+
+ for (iter = peer->path_head, i = 0; NULL != iter; iter = iter->next)
+ i++;
+
+ return i;
+}
+
+
+/**
+ * Iterate all known peers.
+ *
+ * @param iter Iterator.
+ * @param cls Closure for @c iter.
+ */
+void
+GMP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls)
+{
+ GNUNET_CONTAINER_multipeermap_iterate (peers, iter, cls);
+}
+
+
+/**
+ * Get the static string for a peer ID.
+ *
+ * @param peer Peer.
+ *
+ * @return Static string for it's ID.
+ */
+const char *
+GMP_2s (const struct CadetPeer *peer)
+{
+ if (NULL == peer)
+ return "(NULL)";
+ return GNUNET_i2s (GNUNET_PEER_resolve2 (peer->id));
+}
Copied: gnunet/src/cadet/gnunet-service-cadet_peer.h (from rev 33185,
gnunet/src/mesh/gnunet-service-cadet_peer.h)
===================================================================
--- gnunet/src/cadet/gnunet-service-cadet_peer.h
(rev 0)
+++ gnunet/src/cadet/gnunet-service-cadet_peer.h 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -0,0 +1,418 @@
+/*
+ This file is part of GNUnet.
+ (C) 2013 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_peer.h
+ * @brief cadet service; dealing with remote peers
+ * @author Bartlomiej Polot
+ *
+ * All functions in this file should use the prefix GMP (Gnunet Cadet Peer)
+ */
+
+#ifndef GNUNET_SERVICE_CADET_PEER_H
+#define GNUNET_SERVICE_CADET_PEER_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0 /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+/**
+ * Struct containing all information regarding a given peer
+ */
+struct CadetPeer;
+
+/**
+ * Struct containing info about a queued transmission to this peer
+ */
+struct CadetPeerQueue;
+
+#include "gnunet-service-cadet_connection.h"
+
+/**
+ * Callback called when a queued message is sent.
+ *
+ * @param cls Closure.
+ * @param c Connection this message was on.
+ * @param sent Was it really sent? (Could have been canceled)
+ * @param type Type of message sent.
+ * @param pid Packet ID, or 0 if not applicable (create, destroy, etc).
+ * @param fwd Was this a FWD going message?
+ * @param size Size of the message.
+ * @param wait Time spent waiting for core (only the time for THIS message)
+ */
+typedef void (*GMP_sent) (void *cls,
+ struct CadetConnection *c, int sent,
+ uint16_t type, uint32_t pid, int fwd, size_t size,
+ struct GNUNET_TIME_Relative wait);
+
+/******************************************************************************/
+/******************************** API
***********************************/
+/******************************************************************************/
+
+/**
+ * Initialize peer subsystem.
+ *
+ * @param c Configuration.
+ */
+void
+GMP_init (const struct GNUNET_CONFIGURATION_Handle *c);
+
+/**
+ * Shut down the peer subsystem.
+ */
+void
+GMP_shutdown (void);
+
+
+/**
+ * Retrieve the CadetPeer stucture associated with the peer, create one
+ * and insert it in the appropriate structures if the peer is not known yet.
+ *
+ * @param peer_id Full identity of the peer.
+ *
+ * @return Existing or newly created peer structure.
+ */
+struct CadetPeer *
+GMP_get (const struct GNUNET_PeerIdentity *peer_id);
+
+
+/**
+ * Retrieve the CadetPeer stucture associated with the peer, create one
+ * and insert it in the appropriate structures if the peer is not known yet.
+ *
+ * @param peer Short identity of the peer.
+ *
+ * @return Existing or newly created peer structure.
+ */
+struct CadetPeer *
+GMP_get_short (const GNUNET_PEER_Id peer);
+
+/**
+ * Try to establish a new connection to this peer (in its tunnel).
+ * If the peer doesn't have any path to it yet, try to get one.
+ * If the peer already has some path, send a CREATE CONNECTION towards it.
+ *
+ * @param peer Peer to connect to.
+ */
+void
+GMP_connect (struct CadetPeer *peer);
+
+/**
+ * Free a transmission that was already queued with all resources
+ * associated to the request.
+ *
+ * @param queue Queue handler to cancel.
+ * @param clear_cls Is it necessary to free associated cls?
+ * @param sent Was it really sent? (Could have been canceled)
+ * @param pid PID, if relevant (was sent and was a payload message).
+ */
+void
+GMP_queue_destroy (struct CadetPeerQueue *queue, int clear_cls,
+ int sent, uint32_t pid);
+
+/**
+ * @brief Queue and pass message to core when possible.
+ *
+ * @param peer Peer towards which to queue the message.
+ * @param cls Closure (@c type dependant). It will be used by queue_send to
+ * build the message to be sent if not already prebuilt.
+ * @param type Type of the message, 0 for a raw message.
+ * @param size Size of the message.
+ * @param c Connection this message belongs to (cannot be NULL).
+ * @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!)
+ * @param cont Continuation to be called once CORE has taken the message.
+ * @param cont_cls Closure for @c cont.
+ *
+ * @return Handle to cancel the message before it is sent. Once cont is called
+ * message has been sent and therefore the handle is no longer valid.
+ */
+struct CadetPeerQueue *
+GMP_queue_add (struct CadetPeer *peer, void *cls, uint16_t type,
+ uint16_t payload_type, uint32_t payload_id,
+ size_t size, struct CadetConnection *c, int fwd,
+ GMP_sent cont, void *cont_cls);
+
+/**
+ * Cancel all queued messages to a peer that belong to a certain connection.
+ *
+ * @param peer Peer towards whom to cancel.
+ * @param c Connection whose queued messages to cancel. Might be destroyed by
+ * the sent continuation call.
+ */
+void
+GMP_queue_cancel (struct CadetPeer *peer, struct CadetConnection *c);
+
+/**
+ * Get the first message for a connection and unqueue it.
+ *
+ * @param peer Neighboring peer.
+ * @param c Connection.
+ *
+ * @return First message for this connection.
+ */
+struct GNUNET_MessageHeader *
+GMP_connection_pop (struct CadetPeer *peer, struct CadetConnection *c);
+
+void
+GMP_queue_unlock (struct CadetPeer *peer, struct CadetConnection *c);
+
+/**
+ * Set tunnel.
+ *
+ * @param peer Peer.
+ * @param t Tunnel.
+ */
+void
+GMP_set_tunnel (struct CadetPeer *peer, struct CadetTunnel3 *t);
+
+/**
+ * Check whether there is a direct (core level) connection to peer.
+ *
+ * @param peer Peer to check.
+ *
+ * @return #GNUNET_YES if there is a direct connection.
+ */
+int
+GMP_is_neighbor (const struct CadetPeer *peer);
+
+/**
+ * Create and initialize a new tunnel towards a peer, in case it has none.
+ *
+ * Does not generate any traffic, just creates the local data structures.
+ *
+ * @param peer Peer towards which to create the tunnel.
+ */
+void
+GMP_add_tunnel (struct CadetPeer *peer);
+
+/**
+ * Add a connection to a neighboring peer.
+ *
+ * Store that the peer is the first hop of the connection in one
+ * direction and that on peer disconnect the connection must be
+ * notified and destroyed, for it will no longer be valid.
+ *
+ * @param peer Peer to add connection to.
+ * @param c Connection to add.
+ *
+ * @return GNUNET_OK on success.
+ */
+int
+GMP_add_connection (struct CadetPeer *peer, struct CadetConnection *c);
+
+/**
+ * Add the path to the peer and update the path used to reach it in case this
+ * is the shortest.
+ *
+ * @param peer Destination peer to add the path to.
+ * @param path New path to add. Last peer must be the peer in arg 1.
+ * Path will be either used of freed if already known.
+ * @param trusted Do we trust that this path is real?
+ *
+ * @return path if path was taken, pointer to existing duplicate if exists
+ * NULL on error.
+ */
+struct CadetPeerPath *
+GMP_add_path (struct CadetPeer *peer, struct CadetPeerPath *p, int trusted);
+
+/**
+ * Add the path to the origin peer and update the path used to reach it in case
+ * this is the shortest.
+ * The path is given in peer_info -> destination, therefore we turn the path
+ * upside down first.
+ *
+ * @param peer Peer to add the path to, being the origin of the path.
+ * @param path New path to add after being inversed.
+ * Path will be either used or freed.
+ * @param trusted Do we trust that this path is real?
+ *
+ * @return path if path was taken, pointer to existing duplicate if exists
+ * NULL on error.
+ */
+struct CadetPeerPath *
+GMP_add_path_to_origin (struct CadetPeer *peer,
+ struct CadetPeerPath *path,
+ int trusted);
+
+/**
+ * Adds a path to the info of all the peers in the path
+ *
+ * @param p Path to process.
+ * @param confirmed Whether we know if the path works or not.
+ */
+void
+GMP_add_path_to_all (const struct CadetPeerPath *p, int confirmed);
+
+/**
+ * Remove any path to the peer that has the extact same peers as the one given.
+ *
+ * @param peer Peer to remove the path from.
+ * @param path Path to remove. Is always destroyed .
+ */
+void
+GMP_remove_path (struct CadetPeer *peer, struct CadetPeerPath *path);
+
+/**
+ * Remove a connection from a neighboring peer.
+ *
+ * @param peer Peer to remove connection from.
+ * @param c Connection to remove.
+ *
+ * @return GNUNET_OK on success.
+ */
+int
+GMP_remove_connection (struct CadetPeer *peer, const struct CadetConnection
*c);
+
+/**
+ * Start the DHT search for new paths towards the peer: we don't have
+ * enough good connections.
+ *
+ * @param peer Destination peer.
+ */
+void
+GMP_start_search (struct CadetPeer *peer);
+
+/**
+ * Stop the DHT search for new paths towards the peer: we already have
+ * enough good connections.
+ *
+ * @param peer Destination peer.
+ */
+void
+GMP_stop_search (struct CadetPeer *peer);
+
+/**
+ * Get the Full ID of a peer.
+ *
+ * @param peer Peer to get from.
+ *
+ * @return Full ID of peer.
+ */
+const struct GNUNET_PeerIdentity *
+GMP_get_id (const struct CadetPeer *peer);
+
+/**
+ * Get the Short ID of a peer.
+ *
+ * @param peer Peer to get from.
+ *
+ * @return Short ID of peer.
+ */
+GNUNET_PEER_Id
+GMP_get_short_id (const struct CadetPeer *peer);
+
+/**
+ * Get the tunnel towards a peer.
+ *
+ * @param peer Peer to get from.
+ *
+ * @return Tunnel towards peer.
+ */
+struct CadetTunnel3 *
+GMP_get_tunnel (const struct CadetPeer *peer);
+
+/**
+ * Set the hello message.
+ *
+ * @param peer Peer whose message to set.
+ * @param hello Hello message.
+ */
+void
+GMP_set_hello (struct CadetPeer *peer, const struct GNUNET_HELLO_Message
*hello);
+
+/**
+ * Get the hello message.
+ *
+ * @param peer Peer whose message to get.
+ *
+ * @return Hello message.
+ */
+struct GNUNET_HELLO_Message *
+GMP_get_hello (struct CadetPeer *peer);
+
+
+/**
+ * Try to connect to a peer on TRANSPORT level.
+ *
+ * @param peer Peer to whom to connect.
+ */
+void
+GMP_try_connect (struct CadetPeer *peer);
+
+/**
+ * Notify a peer that a link between two other peers is broken. If any path
+ * used that link, eliminate it.
+ *
+ * @param peer Peer affected by the change.
+ * @param peer1 Peer whose link is broken.
+ * @param peer2 Peer whose link is broken.
+ */
+void
+GMP_notify_broken_link (struct CadetPeer *peer,
+ struct GNUNET_PeerIdentity *peer1,
+ struct GNUNET_PeerIdentity *peer2);
+
+/**
+ * Count the number of known paths toward the peer.
+ *
+ * @param peer Peer to get path info.
+ *
+ * @return Number of known paths.
+ */
+unsigned int
+GMP_count_paths (const struct CadetPeer *peer);
+
+/**
+ * Iterate all known peers.
+ *
+ * @param iter Iterator.
+ * @param cls Closure for @c iter.
+ */
+void
+GMP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls);
+
+/**
+ * Get the static string for a peer ID.
+ *
+ * @param peer Peer.
+ *
+ * @return Static string for it's ID.
+ */
+const char *
+GMP_2s (const struct CadetPeer *peer);
+
+
+#if 0 /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* ifndef GNUNET_CADET_SERVICE_PEER_H */
+#endif
+/* end of gnunet-cadet-service_peer.h */
Copied: gnunet/src/cadet/gnunet-service-cadet_tunnel.c (from rev 33185,
gnunet/src/mesh/gnunet-service-cadet_tunnel.c)
===================================================================
--- gnunet/src/cadet/gnunet-service-cadet_tunnel.c
(rev 0)
+++ gnunet/src/cadet/gnunet-service-cadet_tunnel.c 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -0,0 +1,2887 @@
+/*
+ This file is part of GNUnet.
+ (C) 2013 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+#include "gnunet_signatures.h"
+#include "gnunet_statistics_service.h"
+
+#include "cadet_protocol.h"
+#include "cadet_path.h"
+
+#include "gnunet-service-cadet_tunnel.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_channel.h"
+#include "gnunet-service-cadet_peer.h"
+
+#define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__)
+
+#define REKEY_WAIT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5)
+
+#define CONNECTIONS_PER_TUNNEL 3
+
+/******************************************************************************/
+/******************************** STRUCTS
**********************************/
+/******************************************************************************/
+
+struct CadetTChannel
+{
+ struct CadetTChannel *next;
+ struct CadetTChannel *prev;
+ struct CadetChannel *ch;
+};
+
+
+/**
+ * Connection list and metadata.
+ */
+struct CadetTConnection
+{
+ /**
+ * Next in DLL.
+ */
+ struct CadetTConnection *next;
+
+ /**
+ * Prev in DLL.
+ */
+ struct CadetTConnection *prev;
+
+ /**
+ * Connection handle.
+ */
+ struct CadetConnection *c;
+
+ /**
+ * Creation time, to keep oldest connection alive.
+ */
+ struct GNUNET_TIME_Absolute created;
+
+ /**
+ * Connection throughput, to keep fastest connection alive.
+ */
+ uint32_t throughput;
+};
+
+/**
+ * Structure used during a Key eXchange.
+ */
+struct CadetTunnelKXCtx
+{
+ /**
+ * Decryption ("their") old key, for decrypting traffic sent by the
+ * other end before the key exchange started.
+ */
+ struct GNUNET_CRYPTO_SymmetricSessionKey d_key_old;
+
+ /**
+ * Challenge to send in a ping and expect in the pong.
+ */
+ uint32_t challenge;
+};
+
+/**
+ * Struct containing all information regarding a tunnel to a peer.
+ */
+struct CadetTunnel3
+{
+ /**
+ * Endpoint of the tunnel.
+ */
+ struct CadetPeer *peer;
+
+ /**
+ * State of the tunnel connectivity.
+ */
+ enum CadetTunnel3CState cstate;
+
+ /**
+ * State of the tunnel encryption.
+ */
+ enum CadetTunnel3EState estate;
+
+ /**
+ * Key eXchange context.
+ */
+ struct CadetTunnelKXCtx *kx_ctx;
+
+ /**
+ * Encryption ("our") key.
+ */
+ struct GNUNET_CRYPTO_SymmetricSessionKey e_key;
+
+ /**
+ * Decryption ("their") key.
+ */
+ struct GNUNET_CRYPTO_SymmetricSessionKey d_key;
+
+ /**
+ * Task to start the rekey process.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier rekey_task;
+
+ /**
+ * Paths that are actively used to reach the destination peer.
+ */
+ struct CadetTConnection *connection_head;
+ struct CadetTConnection *connection_tail;
+
+ /**
+ * Next connection number.
+ */
+ uint32_t next_cid;
+
+ /**
+ * Channels inside this tunnel.
+ */
+ struct CadetTChannel *channel_head;
+ struct CadetTChannel *channel_tail;
+
+ /**
+ * Channel ID for the next created channel.
+ */
+ CADET_ChannelNumber next_chid;
+
+ /**
+ * Destroy flag: if true, destroy on last message.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier destroy_task;
+
+ /**
+ * Queued messages, to transmit once tunnel gets connected.
+ */
+ struct CadetTunnelDelayed *tq_head;
+ struct CadetTunnelDelayed *tq_tail;
+};
+
+
+/**
+ * Struct used to save messages in a non-ready tunnel to send once connected.
+ */
+struct CadetTunnelDelayed
+{
+ /**
+ * DLL
+ */
+ struct CadetTunnelDelayed *next;
+ struct CadetTunnelDelayed *prev;
+
+ /**
+ * Tunnel.
+ */
+ struct CadetTunnel3 *t;
+
+ /**
+ * Tunnel queue given to the channel to cancel request. Update on
send_queued.
+ */
+ struct CadetTunnel3Queue *tq;
+
+ /**
+ * Message to send.
+ */
+ /* struct GNUNET_MessageHeader *msg; */
+};
+
+
+/**
+ * Handle for messages queued but not yet sent.
+ */
+struct CadetTunnel3Queue
+{
+ /**
+ * Connection queue handle, to cancel if necessary.
+ */
+ struct CadetConnectionQueue *cq;
+
+ /**
+ * Handle in case message hasn't been given to a connection yet.
+ */
+ struct CadetTunnelDelayed *tqd;
+
+ /**
+ * Continuation to call once sent.
+ */
+ GMT_sent cont;
+
+ /**
+ * Closure for @c cont.
+ */
+ void *cont_cls;
+};
+
+
+/******************************************************************************/
+/******************************* GLOBALS
***********************************/
+/******************************************************************************/
+
+/**
+ * Global handle to the statistics service.
+ */
+extern struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Local peer own ID (memory efficient handle).
+ */
+extern GNUNET_PEER_Id myid;
+
+/**
+ * Local peer own ID (full value).
+ */
+extern struct GNUNET_PeerIdentity my_full_id;
+
+
+/**
+ * Don't try to recover tunnels if shutting down.
+ */
+extern int shutting_down;
+
+
+/**
+ * Set of all tunnels, in order to trigger a new exchange on rekey.
+ * Indexed by peer's ID.
+ */
+static struct GNUNET_CONTAINER_MultiPeerMap *tunnels;
+
+/**
+ * Default TTL for payload packets.
+ */
+static unsigned long long default_ttl;
+
+/**
+ * Own private key.
+ */
+const static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
+
+/**
+ * Own ephemeral private key.
+ */
+static struct GNUNET_CRYPTO_EcdhePrivateKey *my_ephemeral_key;
+
+/**
+ * Cached message used to perform a key exchange.
+ */
+static struct GNUNET_CADET_KX_Ephemeral kx_msg;
+
+/**
+ * Task to generate a new ephemeral key.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier rekey_task;
+
+/**
+ * Rekey period.
+ */
+static struct GNUNET_TIME_Relative rekey_period;
+
+/******************************************************************************/
+/******************************** STATIC
***********************************/
+/******************************************************************************/
+
+/**
+ * Get string description for tunnel connectivity state.
+ *
+ * @param cs Tunnel state.
+ *
+ * @return String representation.
+ */
+static const char *
+cstate2s (enum CadetTunnel3CState cs)
+{
+ static char buf[128];
+
+ switch (cs)
+ {
+ case CADET_TUNNEL3_NEW:
+ return "CADET_TUNNEL3_NEW";
+ case CADET_TUNNEL3_SEARCHING:
+ return "CADET_TUNNEL3_SEARCHING";
+ case CADET_TUNNEL3_WAITING:
+ return "CADET_TUNNEL3_WAITING";
+ case CADET_TUNNEL3_READY:
+ return "CADET_TUNNEL3_READY";
+
+ default:
+ sprintf (buf, "%u (UNKNOWN STATE)", cs);
+ return buf;
+ }
+ return "";
+}
+
+
+/**
+ * Get string description for tunnel encryption state.
+ *
+ * @param es Tunnel state.
+ *
+ * @return String representation.
+ */
+static const char *
+estate2s (enum CadetTunnel3EState es)
+{
+ static char buf[128];
+
+ switch (es)
+ {
+ case CADET_TUNNEL3_KEY_UNINITIALIZED:
+ return "CADET_TUNNEL3_KEY_UNINITIALIZED";
+ case CADET_TUNNEL3_KEY_SENT:
+ return "CADET_TUNNEL3_KEY_SENT";
+ case CADET_TUNNEL3_KEY_PING:
+ return "CADET_TUNNEL3_KEY_PING";
+ case CADET_TUNNEL3_KEY_OK:
+ return "CADET_TUNNEL3_KEY_OK";
+
+ default:
+ sprintf (buf, "%u (UNKNOWN STATE)", es);
+ return buf;
+ }
+ return "";
+}
+
+
+/**
+ * @brief Check if tunnel is ready to send traffic.
+ *
+ * Tunnel must be connected and with encryption correctly set up.
+ *
+ * @param t Tunnel to check.
+ *
+ * @return #GNUNET_YES if ready, #GNUNET_NO otherwise
+ */
+static int
+is_ready (struct CadetTunnel3 *t)
+{
+ int ready;
+
+ GMT_debug (t);
+ ready = (CADET_TUNNEL3_READY == t->cstate && CADET_TUNNEL3_KEY_OK ==
t->estate);
+ ready = ready || GMT_is_loopback (t);
+ return ready;
+}
+
+
+/**
+ * Ephemeral key message purpose size.
+ *
+ * @return Size of the part of the ephemeral key message that must be signed.
+ */
+size_t
+ephemeral_purpose_size (void)
+{
+ return sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
+ sizeof (struct GNUNET_TIME_AbsoluteNBO) +
+ sizeof (struct GNUNET_TIME_AbsoluteNBO) +
+ sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) +
+ sizeof (struct GNUNET_PeerIdentity);
+}
+
+
+/**
+ * Size of the encrypted part of a ping message.
+ *
+ * @return Size of the encrypted part of a ping message.
+ */
+size_t
+ping_encryption_size (void)
+{
+ return sizeof (struct GNUNET_PeerIdentity) + sizeof (uint32_t);
+}
+
+
+/**
+ * Get the channel's buffer. ONLY FOR NON-LOOPBACK CHANNELS!!
+ *
+ * @param tch Tunnel's channel handle.
+ *
+ * @return Amount of messages the channel can still buffer towards the client.
+ */
+static unsigned int
+get_channel_buffer (const struct CadetTChannel *tch)
+{
+ int fwd;
+
+ /* If channel is outgoing, is origin in the FWD direction and fwd is YES */
+ fwd = GMCH_is_origin (tch->ch, GNUNET_YES);
+
+ return GMCH_get_buffer (tch->ch, fwd);
+}
+
+
+/**
+ * Get the channel's allowance status.
+ *
+ * @param tch Tunnel's channel handle.
+ *
+ * @return #GNUNET_YES if we allowed the client to send data to us.
+ */
+static int
+get_channel_allowed (const struct CadetTChannel *tch)
+{
+ int fwd;
+
+ /* If channel is outgoing, is origin in the FWD direction and fwd is YES */
+ fwd = GMCH_is_origin (tch->ch, GNUNET_YES);
+
+ return GMCH_get_allowed (tch->ch, fwd);
+}
+
+
+/**
+ * Get the connection's buffer.
+ *
+ * @param tc Tunnel's connection handle.
+ *
+ * @return Amount of messages the connection can still buffer.
+ */
+static unsigned int
+get_connection_buffer (const struct CadetTConnection *tc)
+{
+ int fwd;
+
+ /* If connection is outgoing, is origin in the FWD direction and fwd is YES
*/
+ fwd = GMC_is_origin (tc->c, GNUNET_YES);
+
+ return GMC_get_buffer (tc->c, fwd);
+}
+
+
+/**
+ * Get the connection's allowance.
+ *
+ * @param tc Tunnel's connection handle.
+ *
+ * @return Amount of messages we have allowed the next peer to send us.
+ */
+static unsigned int
+get_connection_allowed (const struct CadetTConnection *tc)
+{
+ int fwd;
+
+ /* If connection is outgoing, is origin in the FWD direction and fwd is YES
*/
+ fwd = GMC_is_origin (tc->c, GNUNET_YES);
+
+ return GMC_get_allowed (tc->c, fwd);
+}
+
+
+/**
+ * Check that a ephemeral key message s well formed and correctly signed.
+ *
+ * @param t Tunnel on which the message came.
+ * @param msg The ephemeral key message.
+ *
+ * @return GNUNET_OK if message is fine, GNUNET_SYSERR otherwise.
+ */
+int
+check_ephemeral (struct CadetTunnel3 *t,
+ const struct GNUNET_CADET_KX_Ephemeral *msg)
+{
+ /* Check message size */
+ if (ntohs (msg->header.size) != sizeof (struct GNUNET_CADET_KX_Ephemeral))
+ return GNUNET_SYSERR;
+
+ /* Check signature size */
+ if (ntohl (msg->purpose.size) != ephemeral_purpose_size ())
+ return GNUNET_SYSERR;
+
+ /* Check origin */
+ if (0 != memcmp (&msg->origin_identity,
+ GMP_get_id (t->peer),
+ sizeof (struct GNUNET_PeerIdentity)))
+ return GNUNET_SYSERR;
+
+ /* Check signature */
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_CADET_KX,
+ &msg->purpose,
+ &msg->signature,
+ &msg->origin_identity.public_key))
+ return GNUNET_SYSERR;
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Encrypt data with the tunnel key.
+ *
+ * @param t Tunnel whose key to use.
+ * @param dst Destination for the encrypted data.
+ * @param src Source of the plaintext. Can overlap with @c dst.
+ * @param size Size of the plaintext.
+ * @param iv Initialization Vector to use.
+ */
+static int
+t_encrypt (struct CadetTunnel3 *t,
+ void *dst, const void *src,
+ size_t size, uint32_t iv)
+{
+ struct GNUNET_CRYPTO_SymmetricInitializationVector siv;
+ size_t out_size;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " t_encrypt start\n");
+ GNUNET_CRYPTO_symmetric_derive_iv (&siv, &t->e_key, &iv, sizeof (iv), NULL);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " t_encrypt IV derived\n");
+ out_size = GNUNET_CRYPTO_symmetric_encrypt (src, size, &t->e_key, &siv, dst);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " t_encrypt end\n");
+
+ return out_size;
+}
+
+
+/**
+ * Decrypt data with the tunnel key.
+ *
+ * @param t Tunnel whose key to use.
+ * @param dst Destination for the plaintext.
+ * @param src Source of the encrypted data. Can overlap with @c dst.
+ * @param size Size of the encrypted data.
+ * @param iv Initialization Vector to use.
+ */
+static int
+t_decrypt (struct CadetTunnel3 *t,
+ void *dst, const void *src,
+ size_t size, uint32_t iv)
+{
+ struct GNUNET_CRYPTO_SymmetricInitializationVector siv;
+ struct GNUNET_CRYPTO_SymmetricSessionKey *key;
+ size_t out_size;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " t_decrypt start\n");
+ if (t->estate == CADET_TUNNEL3_KEY_OK || t->estate == CADET_TUNNEL3_KEY_PING)
+ {
+ key = &t->d_key;
+ }
+ else if (NULL != t->kx_ctx)
+ {
+ key = &t->kx_ctx->d_key_old;
+ }
+ else
+ {
+ GNUNET_STATISTICS_update (stats, "# non decryptable data", 1, GNUNET_NO);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "WARNING got data on %s without a valid key\n",
+ GMT_2s (t));
+ GMT_debug (t);
+ return 0;
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " t_decrypt iv\n");
+ GNUNET_CRYPTO_symmetric_derive_iv (&siv, key, &iv, sizeof (iv), NULL);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " t_decrypt iv done\n");
+ out_size = GNUNET_CRYPTO_symmetric_decrypt (src, size, key, &siv, dst);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " t_decrypt end\n");
+
+ return out_size;
+}
+
+
+/**
+ * Create key material by doing ECDH on the local and remote ephemeral keys.
+ *
+ * @param key_material Where to store the key material.
+ * @param ephemeral_key Peer's public ephemeral key.
+ */
+void
+derive_key_material (struct GNUNET_HashCode *key_material,
+ const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key)
+{
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_ecc_ecdh (my_ephemeral_key,
+ ephemeral_key,
+ key_material))
+ {
+ GNUNET_break (0);
+ }
+}
+
+/**
+ * Create a symmetic key from the identities of both ends and the key material
+ * from ECDH.
+ *
+ * @param key Destination for the generated key.
+ * @param sender ID of the peer that will encrypt with @c key.
+ * @param receiver ID of the peer that will decrypt with @c key.
+ * @param key_material Hash created with ECDH with the ephemeral keys.
+ */
+void
+derive_symmertic (struct GNUNET_CRYPTO_SymmetricSessionKey *key,
+ const struct GNUNET_PeerIdentity *sender,
+ const struct GNUNET_PeerIdentity *receiver,
+ const struct GNUNET_HashCode *key_material)
+{
+ const char salt[] = "CADET kx salt";
+
+ GNUNET_CRYPTO_kdf (key, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
+ salt, sizeof (salt),
+ key_material, sizeof (struct GNUNET_HashCode),
+ sender, sizeof (struct GNUNET_PeerIdentity),
+ receiver, sizeof (struct GNUNET_PeerIdentity),
+ NULL);
+}
+
+/**
+ * Pick a connection on which send the next data message.
+ *
+ * @param t Tunnel on which to send the message.
+ *
+ * @return The connection on which to send the next message.
+ */
+static struct CadetConnection *
+tunnel_get_connection (struct CadetTunnel3 *t)
+{
+ struct CadetTConnection *iter;
+ struct CadetConnection *best;
+ unsigned int qn;
+ unsigned int lowest_q;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel_get_connection %s\n", GMT_2s (t));
+ best = NULL;
+ lowest_q = UINT_MAX;
+ for (iter = t->connection_head; NULL != iter; iter = iter->next)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " connection %s: %u\n",
+ GMC_2s (iter->c), GMC_get_state (iter->c));
+ if (CADET_CONNECTION_READY == GMC_get_state (iter->c))
+ {
+ qn = GMC_get_qn (iter->c, GMC_is_origin (iter->c, GNUNET_YES));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " q_n %u, \n", qn);
+ if (qn < lowest_q)
+ {
+ best = iter->c;
+ lowest_q = qn;
+ }
+ }
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " selected: connection %s\n", GMC_2s (best));
+ return best;
+}
+
+
+/**
+ * Callback called when a queued message is sent.
+ *
+ * Calculates the average time and connection packet tracking.
+ *
+ * @param cls Closure (TunnelQueue handle).
+ * @param c Connection this message was on.
+ * @param q Connection queue handle (unused).
+ * @param type Type of message sent.
+ * @param fwd Was this a FWD going message?
+ * @param size Size of the message.
+ */
+static void
+tun_message_sent (void *cls,
+ struct CadetConnection *c,
+ struct CadetConnectionQueue *q,
+ uint16_t type, int fwd, size_t size)
+{
+ struct CadetTunnel3Queue *qt = cls;
+ struct CadetTunnel3 *t;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "tun_message_sent\n");
+
+ GNUNET_assert (NULL != qt->cont);
+ t = NULL == c ? NULL : GMC_get_tunnel (c);
+ qt->cont (qt->cont_cls, t, qt, type, size);
+ GNUNET_free (qt);
+}
+
+
+/**
+ * Delete a queued message: either was sent or the channel was destroyed
+ * before the tunnel's key exchange had a chance to finish.
+ *
+ * @param tqd Delayed queue handle.
+ */
+static void
+unqueue_data (struct CadetTunnelDelayed *tqd)
+{
+ GNUNET_CONTAINER_DLL_remove (tqd->t->tq_head, tqd->t->tq_tail, tqd);
+ GNUNET_free (tqd);
+}
+
+
+/**
+ * Cache a message to be sent once tunnel is online.
+ *
+ * @param t Tunnel to hold the message.
+ * @param msg Message itself (copy will be made).
+ */
+static struct CadetTunnelDelayed *
+queue_data (struct CadetTunnel3 *t, const struct GNUNET_MessageHeader *msg)
+{
+ struct CadetTunnelDelayed *tqd;
+ uint16_t size = ntohs (msg->size);
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "queue data on Tunnel %s\n", GMT_2s (t));
+
+ if (GNUNET_YES == is_ready (t))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+
+ tqd = GNUNET_malloc (sizeof (struct CadetTunnelDelayed) + size);
+
+ tqd->t = t;
+ memcpy (&tqd[1], msg, size);
+ GNUNET_CONTAINER_DLL_insert_tail (t->tq_head, t->tq_tail, tqd);
+ return tqd;
+}
+
+
+/**
+ * Calculate HMAC.
+ *
+ * @param t Tunnel to get keys from.
+ * @param plaintext Content to HMAC.
+ * @param size Size of @c plaintext.
+ * @param iv Initialization vector for the message.
+ * @param outgoing Is this an outgoing message that we encrypted?
+ * @param hmac Destination to store the HMAC.
+ */
+static void
+t_hmac (struct CadetTunnel3 *t, const void *plaintext, size_t size, uint32_t
iv,
+ int outgoing, struct GNUNET_CADET_Hash *hmac)
+{
+ struct GNUNET_CRYPTO_AuthKey auth_key;
+ static const char ctx[] = "cadet authentication key";
+ struct GNUNET_CRYPTO_SymmetricSessionKey *key;
+ struct GNUNET_HashCode hash;
+
+ key = outgoing ? &t->e_key : &t->d_key;
+ GNUNET_CRYPTO_hmac_derive_key (&auth_key, key,
+ &iv, sizeof (iv),
+ key, sizeof (*key),
+ ctx, sizeof (ctx),
+ NULL);
+ GNUNET_CRYPTO_hmac (&auth_key, plaintext, size, &hash);
+ memcpy (hmac, &hash, sizeof (*hmac));
+}
+
+
+/**
+ * Sends an already built message on a tunnel, encrypting it and
+ * choosing the best connection.
+ *
+ * @param message Message to send. Function modifies it.
+ * @param t Tunnel on which this message is transmitted.
+ * @param c Connection to use (autoselect if NULL).
+ * @param force Force the tunnel to take the message (buffer overfill).
+ * @param cont Continuation to call once message is really sent.
+ * @param cont_cls Closure for @c cont.
+ * @param existing_q In case this a transmission of previously queued data,
+ * this should be TunnelQueue given to the client.
+ * Otherwise, NULL.
+ *
+ * @return Handle to cancel message. NULL if @c cont is NULL.
+ */
+static struct CadetTunnel3Queue *
+send_prebuilt_message (const struct GNUNET_MessageHeader *message,
+ struct CadetTunnel3 *t, struct CadetConnection *c,
+ int force, GMT_sent cont, void *cont_cls,
+ struct CadetTunnel3Queue *existing_q)
+{
+ struct CadetTunnel3Queue *tq;
+ struct GNUNET_CADET_Encrypted *msg;
+ size_t size = ntohs (message->size);
+ char cbuf[sizeof (struct GNUNET_CADET_Encrypted) + size];
+ uint32_t mid;
+ uint32_t iv;
+ uint16_t type;
+ int fwd;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT Send on Tunnel %s\n", GMT_2s (t));
+
+ if (GNUNET_NO == is_ready (t))
+ {
+ struct CadetTunnelDelayed *tqd;
+ /* A non null existing_q indicates sending of queued data.
+ * Should only happen after tunnel becomes ready.
+ */
+ GNUNET_assert (NULL == existing_q);
+ tqd = queue_data (t, message);
+ if (NULL == cont)
+ return NULL;
+ tq = GNUNET_new (struct CadetTunnel3Queue);
+ tq->tqd = tqd;
+ tqd->tq = tq;
+ tq->cont = cont;
+ tq->cont_cls = cont_cls;
+ return tq;
+ }
+
+ GNUNET_assert (GNUNET_NO == GMT_is_loopback (t));
+
+ iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
+ msg = (struct GNUNET_CADET_Encrypted *) cbuf;
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED);
+ msg->iv = iv;
+ GNUNET_assert (t_encrypt (t, &msg[1], message, size, iv) == size);
+ t_hmac (t, &msg[1], size, iv, GNUNET_YES, &msg->hmac);
+ msg->header.size = htons (sizeof (struct GNUNET_CADET_Encrypted) + size);
+
+ if (NULL == c)
+ c = tunnel_get_connection (t);
+ if (NULL == c)
+ {
+ if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task
+ || CADET_TUNNEL3_SEARCHING != t->cstate)
+ {
+ GNUNET_break (0);
+ GMT_debug (t);
+ }
+ return NULL;
+ }
+
+ mid = 0;
+ type = ntohs (message->type);
+ switch (type)
+ {
+ case GNUNET_MESSAGE_TYPE_CADET_DATA:
+ case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK:
+ if (GNUNET_MESSAGE_TYPE_CADET_DATA == type)
+ mid = ntohl (((struct GNUNET_CADET_Data *) message)->mid);
+ else
+ mid = ntohl (((struct GNUNET_CADET_DataACK *) message)->mid);
+ /* Fall thru */
+ case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE:
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE:
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK:
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK:
+ msg->cid = *GMC_get_id (c);
+ msg->ttl = htonl (default_ttl);
+ break;
+ default:
+ GNUNET_break (0);
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "type %s\n", GM_m2s (type));
+
+ fwd = GMC_is_origin (c, GNUNET_YES);
+
+ if (NULL == cont)
+ {
+ GNUNET_break (NULL ==
+ GMC_send_prebuilt_message (&msg->header, type, mid,
+ c, fwd, force, NULL, NULL));
+ return NULL;
+ }
+ if (NULL == existing_q)
+ {
+ tq = GNUNET_new (struct CadetTunnel3Queue); /* FIXME valgrind: leak*/
+ }
+ else
+ {
+ tq = existing_q;
+ tq->tqd = NULL;
+ }
+ tq->cq = GMC_send_prebuilt_message (&msg->header, type, mid, c, fwd, force,
+ &tun_message_sent, tq);
+ tq->cont = cont;
+ tq->cont_cls = cont_cls;
+
+ return tq;
+}
+
+
+/**
+ * Send all cached messages that we can, tunnel is online.
+ *
+ * @param t Tunnel that holds the messages. Cannot be loopback.
+ */
+static void
+send_queued_data (struct CadetTunnel3 *t)
+{
+ struct CadetTunnelDelayed *tqd;
+ struct CadetTunnelDelayed *next;
+ unsigned int room;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "GMT_send_queued_data on tunnel %s\n",
+ GMT_2s (t));
+
+ if (GMT_is_loopback (t))
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ if (GNUNET_NO == is_ready (t))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " not ready yet: %s/%s\n",
+ estate2s (t->estate), cstate2s (t->cstate));
+ return;
+ }
+
+ room = GMT_get_connections_buffer (t);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space: %u\n", room);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " tq head: %p\n", t->tq_head);
+ for (tqd = t->tq_head; NULL != tqd && room > 0; tqd = next)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " sending queued data\n");
+ next = tqd->next;
+ room--;
+ send_prebuilt_message ((struct GNUNET_MessageHeader *) &tqd[1],
+ tqd->t, NULL, GNUNET_YES,
+ NULL != tqd->tq ? tqd->tq->cont : NULL,
+ NULL != tqd->tq ? tqd->tq->cont_cls : NULL,
+ tqd->tq);
+ unqueue_data (tqd);
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT_send_queued_data end\n", GMP_2s
(t->peer));
+}
+
+
+/**
+ * Sends key exchange message on a tunnel, choosing the best connection.
+ * Should not be called on loopback tunnels.
+ *
+ * @param t Tunnel on which this message is transmitted.
+ * @param message Message to send. Function modifies it.
+ */
+static void
+send_kx (struct CadetTunnel3 *t,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct CadetConnection *c;
+ struct GNUNET_CADET_KX *msg;
+ size_t size = ntohs (message->size);
+ char cbuf[sizeof (struct GNUNET_CADET_KX) + size];
+ uint16_t type;
+ int fwd;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT KX on Tunnel %s\n", GMT_2s (t));
+
+ /* Avoid loopback. */
+ if (GMT_is_loopback (t))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " loopback!\n");
+ GNUNET_break (0);
+ return;
+ }
+
+ if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " being destroyed, why bother\n");
+ return;
+ }
+
+ /* Must have a connection. */
+ if (NULL == t->connection_head)
+ {
+ GNUNET_break (CADET_TUNNEL3_SEARCHING == t->cstate);
+ GMT_debug (t);
+ return;
+ }
+
+ msg = (struct GNUNET_CADET_KX *) cbuf;
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_KX);
+ msg->header.size = htons (sizeof (struct GNUNET_CADET_KX) + size);
+ c = tunnel_get_connection (t);
+ if (NULL == c)
+ {
+ GNUNET_break (GNUNET_SCHEDULER_NO_TASK != t->destroy_task
+ || CADET_TUNNEL3_READY != t->cstate);
+ GMT_debug (t);
+ return;
+ }
+ type = ntohs (message->type);
+ switch (type)
+ {
+ case GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL:
+ case GNUNET_MESSAGE_TYPE_CADET_KX_PING:
+ case GNUNET_MESSAGE_TYPE_CADET_KX_PONG:
+ memcpy (&msg[1], message, size);
+ break;
+ default:
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "unkown type %s\n",
+ GM_m2s (type));
+ GNUNET_break (0);
+ }
+
+ fwd = GMC_is_origin (t->connection_head->c, GNUNET_YES);
+ /* TODO save handle and cancel in case of a unneeded retransmission */
+ GMC_send_prebuilt_message (&msg->header, GNUNET_MESSAGE_TYPE_CADET_KX,
+ message->type, c, fwd, GNUNET_YES, NULL, NULL);
+}
+
+
+/**
+ * Send the ephemeral key on a tunnel.
+ *
+ * @param t Tunnel on which to send the key.
+ */
+static void
+send_ephemeral (struct CadetTunnel3 *t)
+{
+ LOG (GNUNET_ERROR_TYPE_INFO, "=> EPHM for %s\n", GMT_2s (t));
+
+ kx_msg.sender_status = htonl (t->estate);
+ send_kx (t, &kx_msg.header);
+}
+
+/**
+ * Send a ping message on a tunnel.
+ *
+ * @param t Tunnel on which to send the ping.
+ */
+static void
+send_ping (struct CadetTunnel3 *t)
+{
+ struct GNUNET_CADET_KX_Ping msg;
+
+ LOG (GNUNET_ERROR_TYPE_INFO, "=> PING for %s\n", GMT_2s (t));
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_KX_PING);
+ msg.iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
+ msg.target = *GMP_get_id (t->peer);
+ msg.nonce = t->kx_ctx->challenge;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " sending %u\n", msg.nonce);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " towards %s\n", GNUNET_i2s (&msg.target));
+ t_encrypt (t, &msg.target, &msg.target, ping_encryption_size(), msg.iv);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " e sending %u\n", msg.nonce);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " e towards %s\n", GNUNET_i2s (&msg.target));
+
+ send_kx (t, &msg.header);
+}
+
+
+/**
+ * Send a pong message on a tunnel.
+ *
+ * @param t Tunnel on which to send the pong.
+ * @param challenge Value sent in the ping that we have to send back.
+ */
+static void
+send_pong (struct CadetTunnel3 *t, uint32_t challenge)
+{
+ struct GNUNET_CADET_KX_Pong msg;
+
+ LOG (GNUNET_ERROR_TYPE_INFO, "=> PONG for %s\n", GMT_2s (t));
+ msg.header.size = htons (sizeof (msg));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_KX_PONG);
+ msg.iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
+ msg.nonce = challenge;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " sending %u\n", msg.nonce);
+ t_encrypt (t, &msg.nonce, &msg.nonce, sizeof (msg.nonce), msg.iv);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " e sending %u\n", msg.nonce);
+
+ send_kx (t, &msg.header);
+}
+
+
+/**
+ * Initiate a rekey with the remote peer.
+ *
+ * @param cls Closure (tunnel).
+ * @param tc TaskContext.
+ */
+static void
+rekey_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct CadetTunnel3 *t = cls;
+
+ t->rekey_task = GNUNET_SCHEDULER_NO_TASK;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Re-key Tunnel %s\n", GMT_2s (t));
+ if (NULL != tc && 0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+ return;
+
+ if (NULL == t->kx_ctx)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " new kx ctx\n");
+ t->kx_ctx = GNUNET_new (struct CadetTunnelKXCtx);
+ t->kx_ctx->challenge =
+ GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
+ t->kx_ctx->d_key_old = t->d_key;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " new challenge for %s: %u\n",
+ GMT_2s (t), t->kx_ctx->challenge);
+ }
+ send_ephemeral (t);
+ switch (t->estate)
+ {
+ case CADET_TUNNEL3_KEY_UNINITIALIZED:
+ t->estate = CADET_TUNNEL3_KEY_SENT;
+ break;
+ case CADET_TUNNEL3_KEY_SENT:
+ break;
+ case CADET_TUNNEL3_KEY_PING:
+ case CADET_TUNNEL3_KEY_OK:
+ send_ping (t);
+ t->estate = CADET_TUNNEL3_KEY_PING;
+ break;
+ default:
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Unexpected state %u\n", t->estate);
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " next call in %s\n",
+ GNUNET_STRINGS_relative_time_to_string (REKEY_WAIT, GNUNET_YES));
+ t->rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_WAIT, &rekey_tunnel, t);
+}
+
+
+/**
+ * Out ephemeral key has changed, create new session key on all tunnels.
+ *
+ * @param cls Closure (size of the hashmap).
+ * @param key Current public key.
+ * @param value Value in the hash map (tunnel).
+ *
+ * @return #GNUNET_YES, so we should continue to iterate,
+ */
+static int
+rekey_iterator (void *cls,
+ const struct GNUNET_PeerIdentity *key,
+ void *value)
+{
+ struct CadetTunnel3 *t = value;
+ struct GNUNET_TIME_Relative delay;
+ long n = (long) cls;
+ uint32_t r;
+
+ if (GNUNET_SCHEDULER_NO_TASK != t->rekey_task)
+ return GNUNET_YES;
+
+ if (GNUNET_YES == GMT_is_loopback (t))
+ return GNUNET_YES;
+
+ r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, (uint32_t) n *
100);
+ delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, r);
+ t->rekey_task = GNUNET_SCHEDULER_add_delayed (delay, &rekey_tunnel, t);
+
+ return GNUNET_YES;
+}
+
+
+/**
+ * Create a new ephemeral key and key message, schedule next rekeying.
+ *
+ * @param cls Closure (unused).
+ * @param tc TaskContext.
+ */
+static void
+rekey (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_TIME_Absolute time;
+ long n;
+
+ rekey_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+ return;
+
+ GNUNET_free_non_null (my_ephemeral_key);
+ my_ephemeral_key = GNUNET_CRYPTO_ecdhe_key_create ();
+
+ time = GNUNET_TIME_absolute_get ();
+ kx_msg.creation_time = GNUNET_TIME_absolute_hton (time);
+ time = GNUNET_TIME_absolute_add (time, rekey_period);
+ time = GNUNET_TIME_absolute_add (time, GNUNET_TIME_UNIT_MINUTES);
+ kx_msg.expiration_time = GNUNET_TIME_absolute_hton (time);
+ GNUNET_CRYPTO_ecdhe_key_get_public (my_ephemeral_key, &kx_msg.ephemeral_key);
+
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_eddsa_sign (my_private_key,
+ &kx_msg.purpose,
+ &kx_msg.signature));
+
+ n = (long) GNUNET_CONTAINER_multipeermap_size (tunnels);
+ GNUNET_CONTAINER_multipeermap_iterate (tunnels, &rekey_iterator, (void *) n);
+
+ rekey_task = GNUNET_SCHEDULER_add_delayed (rekey_period, &rekey, NULL);
+}
+
+
+/**
+ * Called only on shutdown, destroy every tunnel.
+ *
+ * @param cls Closure (unused).
+ * @param key Current public key.
+ * @param value Value in the hash map (tunnel).
+ *
+ * @return #GNUNET_YES, so we should continue to iterate,
+ */
+static int
+destroy_iterator (void *cls,
+ const struct GNUNET_PeerIdentity *key,
+ void *value)
+{
+ struct CadetTunnel3 *t = value;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT_shutdown destroying tunnel at %p\n", t);
+ GMT_destroy (t);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Notify remote peer that we don't know a channel he is talking about,
+ * probably CHANNEL_DESTROY was missed.
+ *
+ * @param t Tunnel on which to notify.
+ * @param gid ID of the channel.
+ */
+static void
+send_channel_destroy (struct CadetTunnel3 *t, unsigned int gid)
+{
+ struct GNUNET_CADET_ChannelManage msg;
+
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
+ msg.header.size = htons (sizeof (msg));
+ msg.chid = htonl (gid);
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "WARNING destroying unknown channel %u on tunnel %s\n",
+ gid, GMT_2s (t));
+ send_prebuilt_message (&msg.header, t, NULL, GNUNET_YES, NULL, NULL, NULL);
+}
+
+
+/**
+ * Demultiplex data per channel and call appropriate channel handler.
+ *
+ * @param t Tunnel on which the data came.
+ * @param msg Data message.
+ * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
+ * #GNUNET_YES if message is FWD on the respective channel
(loopback)
+ * #GNUNET_NO if message is BCK on the respective channel (loopback)
+ * #GNUNET_SYSERR if message on a one-ended channel (remote)
+ */
+static void
+handle_data (struct CadetTunnel3 *t,
+ const struct GNUNET_CADET_Data *msg,
+ int fwd)
+{
+ struct CadetChannel *ch;
+ size_t size;
+
+ /* Check size */
+ size = ntohs (msg->header.size);
+ if (size <
+ sizeof (struct GNUNET_CADET_Data) +
+ sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break (0);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " payload of type %s\n",
+ GM_m2s (ntohs (msg[1].header.type)));
+
+ /* Check channel */
+ ch = GMT_get_channel (t, ntohl (msg->chid));
+ if (NULL == ch)
+ {
+ GNUNET_STATISTICS_update (stats, "# data on unknown channel",
+ 1, GNUNET_NO);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel 0x%X unknown\n",
+ ntohl (msg->chid));
+ send_channel_destroy (t, ntohl (msg->chid));
+ return;
+ }
+
+ GMCH_handle_data (ch, msg, fwd);
+}
+
+
+/**
+ * Demultiplex data ACKs per channel and update appropriate channel buffer
info.
+ *
+ * @param t Tunnel on which the DATA ACK came.
+ * @param msg DATA ACK message.
+ * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
+ * #GNUNET_YES if message is FWD on the respective channel
(loopback)
+ * #GNUNET_NO if message is BCK on the respective channel (loopback)
+ * #GNUNET_SYSERR if message on a one-ended channel (remote)
+ */
+static void
+handle_data_ack (struct CadetTunnel3 *t,
+ const struct GNUNET_CADET_DataACK *msg,
+ int fwd)
+{
+ struct CadetChannel *ch;
+ size_t size;
+
+ /* Check size */
+ size = ntohs (msg->header.size);
+ if (size != sizeof (struct GNUNET_CADET_DataACK))
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ /* Check channel */
+ ch = GMT_get_channel (t, ntohl (msg->chid));
+ if (NULL == ch)
+ {
+ GNUNET_STATISTICS_update (stats, "# data ack on unknown channel",
+ 1, GNUNET_NO);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n",
+ ntohl (msg->chid));
+ return;
+ }
+
+ GMCH_handle_data_ack (ch, msg, fwd);
+}
+
+
+/**
+ * Handle channel create.
+ *
+ * @param t Tunnel on which the data came.
+ * @param msg Data message.
+ */
+static void
+handle_ch_create (struct CadetTunnel3 *t,
+ const struct GNUNET_CADET_ChannelCreate *msg)
+{
+ struct CadetChannel *ch;
+ size_t size;
+
+ /* Check size */
+ size = ntohs (msg->header.size);
+ if (size != sizeof (struct GNUNET_CADET_ChannelCreate))
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ /* Check channel */
+ ch = GMT_get_channel (t, ntohl (msg->chid));
+ if (NULL != ch && ! GMT_is_loopback (t))
+ {
+ /* Probably a retransmission, safe to ignore */
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " already exists...\n");
+ }
+ ch = GMCH_handle_create (t, msg);
+ if (NULL != ch)
+ GMT_add_channel (t, ch);
+}
+
+
+
+/**
+ * Handle channel NACK: check correctness and call channel handler for NACKs.
+ *
+ * @param t Tunnel on which the NACK came.
+ * @param msg NACK message.
+ */
+static void
+handle_ch_nack (struct CadetTunnel3 *t,
+ const struct GNUNET_CADET_ChannelManage *msg)
+{
+ struct CadetChannel *ch;
+ size_t size;
+
+ /* Check size */
+ size = ntohs (msg->header.size);
+ if (size != sizeof (struct GNUNET_CADET_ChannelManage))
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ /* Check channel */
+ ch = GMT_get_channel (t, ntohl (msg->chid));
+ if (NULL == ch)
+ {
+ GNUNET_STATISTICS_update (stats, "# channel NACK on unknown channel",
+ 1, GNUNET_NO);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n",
+ ntohl (msg->chid));
+ return;
+ }
+
+ GMCH_handle_nack (ch);
+}
+
+
+/**
+ * Handle a CHANNEL ACK (SYNACK/ACK).
+ *
+ * @param t Tunnel on which the CHANNEL ACK came.
+ * @param msg CHANNEL ACK message.
+ * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
+ * #GNUNET_YES if message is FWD on the respective channel
(loopback)
+ * #GNUNET_NO if message is BCK on the respective channel (loopback)
+ * #GNUNET_SYSERR if message on a one-ended channel (remote)
+ */
+static void
+handle_ch_ack (struct CadetTunnel3 *t,
+ const struct GNUNET_CADET_ChannelManage *msg,
+ int fwd)
+{
+ struct CadetChannel *ch;
+ size_t size;
+
+ /* Check size */
+ size = ntohs (msg->header.size);
+ if (size != sizeof (struct GNUNET_CADET_ChannelManage))
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ /* Check channel */
+ ch = GMT_get_channel (t, ntohl (msg->chid));
+ if (NULL == ch)
+ {
+ GNUNET_STATISTICS_update (stats, "# channel ack on unknown channel",
+ 1, GNUNET_NO);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n",
+ ntohl (msg->chid));
+ return;
+ }
+
+ GMCH_handle_ack (ch, msg, fwd);
+}
+
+
+
+/**
+ * Handle a channel destruction message.
+ *
+ * @param t Tunnel on which the message came.
+ * @param msg Channel destroy message.
+ * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
+ * #GNUNET_YES if message is FWD on the respective channel
(loopback)
+ * #GNUNET_NO if message is BCK on the respective channel (loopback)
+ * #GNUNET_SYSERR if message on a one-ended channel (remote)
+ */
+static void
+handle_ch_destroy (struct CadetTunnel3 *t,
+ const struct GNUNET_CADET_ChannelManage *msg,
+ int fwd)
+{
+ struct CadetChannel *ch;
+ size_t size;
+
+ /* Check size */
+ size = ntohs (msg->header.size);
+ if (size != sizeof (struct GNUNET_CADET_ChannelManage))
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ /* Check channel */
+ ch = GMT_get_channel (t, ntohl (msg->chid));
+ if (NULL == ch)
+ {
+ /* Probably a retransmission, safe to ignore */
+ return;
+ }
+
+ GMCH_handle_destroy (ch, msg, fwd);
+}
+
+
+/**
+ * The peer's ephemeral key has changed: update the symmetrical keys.
+ *
+ * @param t Tunnel this message came on.
+ * @param msg Key eXchange message.
+ */
+static void
+handle_ephemeral (struct CadetTunnel3 *t,
+ const struct GNUNET_CADET_KX_Ephemeral *msg)
+{
+ struct GNUNET_HashCode km;
+ LOG (GNUNET_ERROR_TYPE_INFO, "<=== EPHM for %s\n", GMT_2s (t));
+
+ if (GNUNET_OK != check_ephemeral (t, msg))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ derive_key_material (&km, &msg->ephemeral_key);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " km is %s\n", GNUNET_h2s (&km));
+ derive_symmertic (&t->e_key, &my_full_id, GMP_get_id (t->peer), &km);
+ derive_symmertic (&t->d_key, GMP_get_id (t->peer), &my_full_id, &km);
+ if (CADET_TUNNEL3_KEY_SENT == t->estate)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " our key was sent, send ping\n");
+ send_ping (t);
+ t->estate = CADET_TUNNEL3_KEY_PING;
+ }
+}
+
+
+/**
+ * Peer wants to check our symmetrical keys by sending an encrypted challenge.
+ * Answer with by retransmitting the challenge with the "opposite" key.
+ *
+ * @param t Tunnel this message came on.
+ * @param msg Key eXchange Ping message.
+ */
+static void
+handle_ping (struct CadetTunnel3 *t,
+ const struct GNUNET_CADET_KX_Ping *msg)
+{
+ struct GNUNET_CADET_KX_Ping res;
+
+ if (ntohs (msg->header.size) != sizeof (res))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+
+ LOG (GNUNET_ERROR_TYPE_INFO, "<=== PING for %s\n", GMT_2s (t));
+ t_decrypt (t, &res.target, &msg->target, ping_encryption_size (), msg->iv);
+ if (0 != memcmp (&my_full_id, &res.target, sizeof (my_full_id)))
+ {
+ // FIXME: move to debug
+ GNUNET_STATISTICS_update (stats, "# malformed PINGs", 1, GNUNET_NO);
+ LOG (GNUNET_ERROR_TYPE_WARNING, " malformed PING on %s\n", GMT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_WARNING, " e got %u\n", msg->nonce);
+ LOG (GNUNET_ERROR_TYPE_WARNING, " e towards %s\n", GNUNET_i2s
(&msg->target));
+ LOG (GNUNET_ERROR_TYPE_WARNING, " got %u\n", res.nonce);
+ LOG (GNUNET_ERROR_TYPE_WARNING, " towards %s\n", GNUNET_i2s
(&res.target));
+ return;
+ }
+
+ send_pong (t, res.nonce);
+}
+
+
+/**
+ * Peer has answer to our challenge.
+ * If answer is successful, consider the key exchange finished and clean
+ * up all related state.
+ *
+ * @param t Tunnel this message came on.
+ * @param msg Key eXchange Pong message.
+ */
+static void
+handle_pong (struct CadetTunnel3 *t,
+ const struct GNUNET_CADET_KX_Pong *msg)
+{
+ uint32_t challenge;
+
+ LOG (GNUNET_ERROR_TYPE_INFO, "<=== PONG for %s\n", GMT_2s (t));
+ if (GNUNET_SCHEDULER_NO_TASK == t->rekey_task)
+ {
+ GNUNET_STATISTICS_update (stats, "# duplicate PONG messages", 1,
GNUNET_NO);
+ return;
+ }
+ t_decrypt (t, &challenge, &msg->nonce, sizeof (uint32_t), msg->iv);
+
+ if (challenge != t->kx_ctx->challenge)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Wrong PONG challenge\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "PONG: %u (e: %u). Expected: %u.\n",
+ challenge, msg->nonce, t->kx_ctx->challenge);
+ GNUNET_break_op (0);
+ return;
+ }
+ GNUNET_SCHEDULER_cancel (t->rekey_task);
+ t->rekey_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_free (t->kx_ctx);
+ t->kx_ctx = NULL;
+ GMT_change_estate (t, CADET_TUNNEL3_KEY_OK);
+}
+
+
+/**
+ * Demultiplex by message type and call appropriate handler for a message
+ * towards a channel of a local tunnel.
+ *
+ * @param t Tunnel this message came on.
+ * @param msgh Message header.
+ * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
+ * #GNUNET_YES if message is FWD on the respective channel
(loopback)
+ * #GNUNET_NO if message is BCK on the respective channel (loopback)
+ * #GNUNET_SYSERR if message on a one-ended channel (remote)
+ */
+static void
+handle_decrypted (struct CadetTunnel3 *t,
+ const struct GNUNET_MessageHeader *msgh,
+ int fwd)
+{
+ uint16_t type;
+
+ type = ntohs (msgh->type);
+ LOG (GNUNET_ERROR_TYPE_INFO, "<=== %s on %s\n", GM_m2s (type), GMT_2s (t));
+
+ switch (type)
+ {
+ case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE:
+ /* Do nothing, connection aleady got updated. */
+ GNUNET_STATISTICS_update (stats, "# keepalives received", 1, GNUNET_NO);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_DATA:
+ /* Don't send hop ACK, wait for client to ACK */
+ handle_data (t, (struct GNUNET_CADET_Data *) msgh, fwd);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK:
+ handle_data_ack (t, (struct GNUNET_CADET_DataACK *) msgh, fwd);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE:
+ handle_ch_create (t,
+ (struct GNUNET_CADET_ChannelCreate *) msgh);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK:
+ handle_ch_nack (t,
+ (struct GNUNET_CADET_ChannelManage *) msgh);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK:
+ handle_ch_ack (t,
+ (struct GNUNET_CADET_ChannelManage *) msgh,
+ fwd);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
+ handle_ch_destroy (t,
+ (struct GNUNET_CADET_ChannelManage *) msgh,
+ fwd);
+ break;
+
+ default:
+ GNUNET_break_op (0);
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "end-to-end message not known (%u)\n",
+ ntohs (msgh->type));
+ GMT_debug (t);
+ }
+}
+
+/******************************************************************************/
+/******************************** API
***********************************/
+/******************************************************************************/
+
+/**
+ * Decrypt and demultiplex by message type. Call appropriate handler
+ * for every message.
+ *
+ * @param t Tunnel this message came on.
+ * @param msg Encrypted message.
+ */
+void
+GMT_handle_encrypted (struct CadetTunnel3 *t,
+ const struct GNUNET_CADET_Encrypted *msg)
+{
+ size_t size = ntohs (msg->header.size);
+ size_t payload_size = size - sizeof (struct GNUNET_CADET_Encrypted);
+ size_t decrypted_size;
+ char cbuf [payload_size];
+ struct GNUNET_MessageHeader *msgh;
+ unsigned int off;
+ struct GNUNET_CADET_Hash hmac;
+
+ decrypted_size = t_decrypt (t, cbuf, &msg[1], payload_size, msg->iv);
+ t_hmac (t, &msg[1], payload_size, msg->iv, GNUNET_NO, &hmac);
+ if (0 != memcmp (&hmac, &msg->hmac, sizeof (hmac)))
+ {
+ /* checksum failed */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed checksum validation for a message on tunnel `%s'\n",
+ GMT_2s (t));
+ GNUNET_STATISTICS_update (stats, "# wrong HMAC", 1, GNUNET_NO);
+ return;
+ }
+ off = 0;
+ while (off < decrypted_size)
+ {
+ msgh = (struct GNUNET_MessageHeader *) &cbuf[off];
+ handle_decrypted (t, msgh, GNUNET_SYSERR);
+ off += ntohs (msgh->size);
+ }
+}
+
+
+/**
+ * Demultiplex an encapsulated KX message by message type.
+ *
+ * @param t Tunnel on which the message came.
+ * @param message Payload of KX message.
+ */
+void
+GMT_handle_kx (struct CadetTunnel3 *t,
+ const struct GNUNET_MessageHeader *message)
+{
+ uint16_t type;
+
+ type = ntohs (message->type);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "kx message received\n", type);
+ switch (type)
+ {
+ case GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL:
+ handle_ephemeral (t, (struct GNUNET_CADET_KX_Ephemeral *) message);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_KX_PING:
+ handle_ping (t, (struct GNUNET_CADET_KX_Ping *) message);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_CADET_KX_PONG:
+ handle_pong (t, (struct GNUNET_CADET_KX_Pong *) message);
+ break;
+
+ default:
+ GNUNET_break_op (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "kx message not known (%u)\n", type);
+ }
+}
+
+
+/**
+ * Initialize the tunnel subsystem.
+ *
+ * @param c Configuration handle.
+ * @param key ECC private key, to derive all other keys and do crypto.
+ */
+void
+GMT_init (const struct GNUNET_CONFIGURATION_Handle *c,
+ const struct GNUNET_CRYPTO_EddsaPrivateKey *key)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (c, "CADET", "DEFAULT_TTL",
+ &default_ttl))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
+ "CADET", "DEFAULT_TTL", "USING DEFAULT");
+ default_ttl = 64;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (c, "CADET", "REKEY_PERIOD",
+ &rekey_period))
+ {
+ rekey_period = GNUNET_TIME_UNIT_DAYS;
+ }
+
+ my_private_key = key;
+ kx_msg.header.size = htons (sizeof (kx_msg));
+ kx_msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL);
+ kx_msg.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CADET_KX);
+ kx_msg.purpose.size = htonl (ephemeral_purpose_size ());
+ kx_msg.origin_identity = my_full_id;
+ rekey_task = GNUNET_SCHEDULER_add_now (&rekey, NULL);
+
+ tunnels = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES);
+}
+
+
+/**
+ * Shut down the tunnel subsystem.
+ */
+void
+GMT_shutdown (void)
+{
+ if (GNUNET_SCHEDULER_NO_TASK != rekey_task)
+ {
+ GNUNET_SCHEDULER_cancel (rekey_task);
+ rekey_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_CONTAINER_multipeermap_iterate (tunnels, &destroy_iterator, NULL);
+ GNUNET_CONTAINER_multipeermap_destroy (tunnels);
+}
+
+
+/**
+ * Create a tunnel.
+ *
+ * @param destination Peer this tunnel is towards.
+ */
+struct CadetTunnel3 *
+GMT_new (struct CadetPeer *destination)
+{
+ struct CadetTunnel3 *t;
+
+ t = GNUNET_new (struct CadetTunnel3);
+ t->next_chid = 0;
+ t->peer = destination;
+
+ if (GNUNET_OK !=
+ GNUNET_CONTAINER_multipeermap_put (tunnels, GMP_get_id (destination), t,
+
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
+ {
+ GNUNET_break (0);
+ GNUNET_free (t);
+ return NULL;
+ }
+ return t;
+}
+
+
+/**
+ * Change the tunnel's connection state.
+ *
+ * @param t Tunnel whose connection state to change.
+ * @param cstate New connection state.
+ */
+void
+GMT_change_cstate (struct CadetTunnel3* t, enum CadetTunnel3CState cstate)
+{
+ if (NULL == t)
+ return;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s cstate %s => %s\n",
+ GMP_2s (t->peer), cstate2s (t->cstate), cstate2s (cstate));
+ if (myid != GMP_get_short_id (t->peer) &&
+ CADET_TUNNEL3_READY != t->cstate &&
+ CADET_TUNNEL3_READY == cstate)
+ {
+ t->cstate = cstate;
+ if (CADET_TUNNEL3_KEY_OK == t->estate)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered send queued data\n");
+ send_queued_data (t);
+ }
+ else if (CADET_TUNNEL3_KEY_UNINITIALIZED == t->estate)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered rekey\n");
+ rekey_tunnel (t, NULL);
+ }
+ }
+ t->cstate = cstate;
+
+ if (CADET_TUNNEL3_READY == cstate
+ && CONNECTIONS_PER_TUNNEL <= GMT_count_connections (t))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered stop dht\n");
+ GMP_stop_search (t->peer);
+ }
+}
+
+/**
+ * Change the tunnel encryption state.
+ *
+ * @param t Tunnel whose encryption state to change.
+ * @param state New encryption state.
+ */
+void
+GMT_change_estate (struct CadetTunnel3* t, enum CadetTunnel3EState state)
+{
+ if (NULL == t)
+ return;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Tunnel %s estate was %s\n",
+ GMP_2s (t->peer), estate2s (t->estate));
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Tunnel %s estate is now %s\n",
+ GMP_2s (t->peer), estate2s (state));
+ if (myid != GMP_get_short_id (t->peer) &&
+ CADET_TUNNEL3_KEY_OK != t->estate && CADET_TUNNEL3_KEY_OK == state)
+ {
+ t->estate = state;
+ send_queued_data (t);
+ return;
+ }
+ t->estate = state;
+}
+
+
+/**
+ * @brief Check if tunnel has too many connections, and remove one if
necessary.
+ *
+ * Currently this means the newest connection, unless it is a direct one.
+ * Implemented as a task to avoid freeing a connection that is in the middle
+ * of being created/processed.
+ *
+ * @param cls Closure (Tunnel to check).
+ * @param tc Task context.
+ */
+static void
+trim_connections (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct CadetTunnel3 *t = cls;
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ if (GMT_count_connections (t) > 2 * CONNECTIONS_PER_TUNNEL)
+ {
+ struct CadetTConnection *iter;
+ struct CadetTConnection *c;
+
+ for (c = iter = t->connection_head; NULL != iter; iter = iter->next)
+ {
+ if ((NULL == c || iter->created.abs_value_us > c->created.abs_value_us)
+ && GNUNET_NO == GMC_is_direct (iter->c))
+ {
+ c = iter;
+ }
+ }
+ if (NULL != c)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Too many connections on tunnel %s\n",
+ GMT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying connection %s\n",
+ GMC_2s (c->c));
+ GMC_destroy (c->c);
+ }
+ else
+ {
+ GNUNET_break (0);
+ }
+ }
+}
+
+
+/**
+ * Add a connection to a tunnel.
+ *
+ * @param t Tunnel.
+ * @param c Connection.
+ */
+void
+GMT_add_connection (struct CadetTunnel3 *t, struct CadetConnection *c)
+{
+ struct CadetTConnection *aux;
+
+ GNUNET_assert (NULL != c);
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "add connection %s\n", GMC_2s (c));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " to tunnel %s\n", GMT_2s (t));
+ for (aux = t->connection_head; aux != NULL; aux = aux->next)
+ if (aux->c == c)
+ return;
+
+ aux = GNUNET_new (struct CadetTConnection);
+ aux->c = c;
+ aux->created = GNUNET_TIME_absolute_get ();
+
+ GNUNET_CONTAINER_DLL_insert (t->connection_head, t->connection_tail, aux);
+
+ GNUNET_SCHEDULER_add_now (&trim_connections, t);
+}
+
+
+/**
+ * Mark a path as no longer valid for this tunnel: has been tried and failed.
+ *
+ * @param t Tunnel to update.
+ * @param path Invalid path to remove. Is destroyed after removal.
+ */
+void
+GMT_remove_path (struct CadetTunnel3 *t, struct CadetPeerPath *path)
+{
+ GMP_remove_path (t->peer, path);
+}
+
+
+/**
+ * Remove a connection from a tunnel.
+ *
+ * @param t Tunnel.
+ * @param c Connection.
+ */
+void
+GMT_remove_connection (struct CadetTunnel3 *t,
+ struct CadetConnection *c)
+{
+ struct CadetTConnection *aux;
+ struct CadetTConnection *next;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing connection %s from tunnel %s\n",
+ GMC_2s (c), GMT_2s (t));
+ for (aux = t->connection_head; aux != NULL; aux = next)
+ {
+ next = aux->next;
+ if (aux->c == c)
+ {
+ GNUNET_CONTAINER_DLL_remove (t->connection_head, t->connection_tail,
aux);
+ GNUNET_free (aux);
+ }
+ }
+
+ /* Start new connections if needed */
+ if (CONNECTIONS_PER_TUNNEL < GMT_count_connections (t)
+ && GNUNET_SCHEDULER_NO_TASK == t->destroy_task
+ && CADET_TUNNEL3_SHUTDOWN != t->cstate
+ && GNUNET_NO == shutting_down)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " no more connections, getting new ones\n");
+ t->cstate = CADET_TUNNEL3_SEARCHING;
+ GMP_connect (t->peer);
+ return;
+ }
+
+ /* If not marked as ready, no change is needed */
+ if (CADET_TUNNEL3_READY != t->cstate)
+ return;
+
+ /* Check if any connection is ready to maintaing cstate */
+ for (aux = t->connection_head; aux != NULL; aux = aux->next)
+ if (CADET_CONNECTION_READY == GMC_get_state (aux->c))
+ return;
+
+ t->cstate = CADET_TUNNEL3_WAITING;
+}
+
+
+/**
+ * Add a channel to a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel.
+ */
+void
+GMT_add_channel (struct CadetTunnel3 *t, struct CadetChannel *ch)
+{
+ struct CadetTChannel *aux;
+
+ GNUNET_assert (NULL != ch);
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding channel %p to tunnel %p\n", ch, t);
+
+ for (aux = t->channel_head; aux != NULL; aux = aux->next)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " already there %p\n", aux->ch);
+ if (aux->ch == ch)
+ return;
+ }
+
+ aux = GNUNET_new (struct CadetTChannel);
+ aux->ch = ch;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " adding %p to %p\n", aux, t->channel_head);
+ GNUNET_CONTAINER_DLL_insert_tail (t->channel_head, t->channel_tail, aux);
+
+ if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task)
+ {
+ GNUNET_SCHEDULER_cancel (t->destroy_task);
+ t->destroy_task = GNUNET_SCHEDULER_NO_TASK;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " undo destroy!\n");
+ }
+}
+
+
+/**
+ * Remove a channel from a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel.
+ */
+void
+GMT_remove_channel (struct CadetTunnel3 *t, struct CadetChannel *ch)
+{
+ struct CadetTChannel *aux;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing channel %p from tunnel %p\n", ch, t);
+ for (aux = t->channel_head; aux != NULL; aux = aux->next)
+ {
+ if (aux->ch == ch)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " found! %s\n", GMCH_2s (ch));
+ GNUNET_CONTAINER_DLL_remove (t->channel_head, t->channel_tail, aux);
+ GNUNET_free (aux);
+ return;
+ }
+ }
+}
+
+
+/**
+ * Search for a channel by global ID.
+ *
+ * @param t Tunnel containing the channel.
+ * @param chid Public channel number.
+ *
+ * @return channel handler, NULL if doesn't exist
+ */
+struct CadetChannel *
+GMT_get_channel (struct CadetTunnel3 *t, CADET_ChannelNumber chid)
+{
+ struct CadetTChannel *iter;
+
+ if (NULL == t)
+ return NULL;
+
+ for (iter = t->channel_head; NULL != iter; iter = iter->next)
+ {
+ if (GMCH_get_id (iter->ch) == chid)
+ break;
+ }
+
+ return NULL == iter ? NULL : iter->ch;
+}
+
+
+/**
+ * @brief Destroy a tunnel and free all resources.
+ *
+ * Should only be called a while after the tunnel has been marked as destroyed,
+ * in case there is a new channel added to the same peer shortly after marking
+ * the tunnel. This way we avoid a new public key handshake.
+ *
+ * @param cls Closure (tunnel to destroy).
+ * @param tc Task context.
+ */
+static void
+delayed_destroy (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct CadetTunnel3 *t = cls;
+ struct CadetTConnection *iter;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "delayed destroying tunnel %p\n", t);
+ if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Not destroying tunnel, due to shutdown. "
+ "Tunnel at %p should have been freed by GMT_shutdown\n", t);
+ return;
+ }
+ t->destroy_task = GNUNET_SCHEDULER_NO_TASK;
+ t->cstate = CADET_TUNNEL3_SHUTDOWN;
+
+ for (iter = t->connection_head; NULL != iter; iter = iter->next)
+ {
+ GMC_send_destroy (iter->c);
+ }
+ GMT_destroy (t);
+}
+
+
+/**
+ * Tunnel is empty: destroy it.
+ *
+ * Notifies all connections about the destruction.
+ *
+ * @param t Tunnel to destroy.
+ */
+void
+GMT_destroy_empty (struct CadetTunnel3 *t)
+{
+ if (GNUNET_YES == shutting_down)
+ return; /* Will be destroyed immediately anyway */
+
+ if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Tunnel %s is already scheduled for destruction\n",
+ GMT_2s (t));
+ GNUNET_break (0);
+ /* should never happen, tunnel can only become empty once, and the
+ * task identifier should be NO_TASK (cleaned when the tunnel was created
+ * or became un-empty)
+ */
+ return;
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s empty: destroying scheduled\n",
+ GMT_2s (t));
+
+ t->destroy_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
+ &delayed_destroy, t);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduled destroy of %p as %llX\n",
+ t, t->destroy_task);
+}
+
+
+/**
+ * Destroy tunnel if empty (no more channels).
+ *
+ * @param t Tunnel to destroy if empty.
+ */
+void
+GMT_destroy_if_empty (struct CadetTunnel3 *t)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s destroy if empty\n", GMT_2s (t));
+ if (1 < GMT_count_channels (t))
+ return;
+
+ GMT_destroy_empty (t);
+}
+
+
+/**
+ * Destroy the tunnel.
+ *
+ * This function does not generate any warning traffic to clients or peers.
+ *
+ * Tasks:
+ * Cancel messages belonging to this tunnel queued to neighbors.
+ * Free any allocated resources linked to the tunnel.
+ *
+ * @param t The tunnel to destroy.
+ */
+void
+GMT_destroy (struct CadetTunnel3 *t)
+{
+ struct CadetTConnection *iter_c;
+ struct CadetTConnection *next_c;
+ struct CadetTChannel *iter_ch;
+ struct CadetTChannel *next_ch;
+
+ if (NULL == t)
+ return;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying tunnel %s\n", GMP_2s (t->peer));
+
+ GNUNET_break (GNUNET_YES ==
+ GNUNET_CONTAINER_multipeermap_remove (tunnels,
+ GMP_get_id (t->peer),
t));
+
+ for (iter_c = t->connection_head; NULL != iter_c; iter_c = next_c)
+ {
+ next_c = iter_c->next;
+ GMC_destroy (iter_c->c);
+ }
+ for (iter_ch = t->channel_head; NULL != iter_ch; iter_ch = next_ch)
+ {
+ next_ch = iter_ch->next;
+ GMCH_destroy (iter_ch->ch);
+ /* Should only happen on shutdown, but it's ok. */
+ }
+
+ if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "cancelling %llX\n", t->destroy_task);
+ GNUNET_SCHEDULER_cancel (t->destroy_task);
+ t->destroy_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ GNUNET_STATISTICS_update (stats, "# tunnels", -1, GNUNET_NO);
+ GMP_set_tunnel (t->peer, NULL);
+
+ if (GNUNET_SCHEDULER_NO_TASK != t->rekey_task)
+ {
+ GNUNET_SCHEDULER_cancel (t->rekey_task);
+ t->rekey_task = GNUNET_SCHEDULER_NO_TASK;
+ if (NULL != t->kx_ctx)
+ GNUNET_free (t->kx_ctx);
+ else
+ GNUNET_break (0);
+ }
+
+ GNUNET_free (t);
+}
+
+
+/**
+ * @brief Use the given path for the tunnel.
+ * Update the next and prev hops (and RCs).
+ * (Re)start the path refresh in case the tunnel is locally owned.
+ *
+ * @param t Tunnel to update.
+ * @param p Path to use.
+ *
+ * @return Connection created.
+ */
+struct CadetConnection *
+GMT_use_path (struct CadetTunnel3 *t, struct CadetPeerPath *p)
+{
+ struct CadetConnection *c;
+ struct GNUNET_CADET_Hash cid;
+ unsigned int own_pos;
+
+ if (NULL == t || NULL == p)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+
+ if (CADET_TUNNEL3_SHUTDOWN == t->cstate)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+
+ for (own_pos = 0; own_pos < p->length; own_pos++)
+ {
+ if (p->peers[own_pos] == myid)
+ break;
+ }
+ if (own_pos >= p->length)
+ {
+ GNUNET_break_op (0);
+ return NULL;
+ }
+
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, &cid, sizeof (cid));
+ c = GMC_new (&cid, t, p, own_pos);
+ if (NULL == c)
+ {
+ /* Path was flawed */
+ return NULL;
+ }
+ GMT_add_connection (t, c);
+ return c;
+}
+
+
+/**
+ * Count established (ready) connections of a tunnel.
+ *
+ * @param t Tunnel on which to count.
+ *
+ * @return Number of connections.
+ */
+unsigned int
+GMT_count_connections (struct CadetTunnel3 *t)
+{
+ struct CadetTConnection *iter;
+ unsigned int count;
+
+ if (NULL == t)
+ return 0;
+
+ for (count = 0, iter = t->connection_head; NULL != iter; iter = iter->next)
+ if (CADET_CONNECTION_DESTROYED != GMC_get_state (iter->c))
+ count++;
+
+ return count;
+}
+
+/**
+ * Count channels of a tunnel.
+ *
+ * @param t Tunnel on which to count.
+ *
+ * @return Number of channels.
+ */
+unsigned int
+GMT_count_channels (struct CadetTunnel3 *t)
+{
+ struct CadetTChannel *iter;
+ unsigned int count;
+
+ for (count = 0, iter = t->channel_head;
+ NULL != iter;
+ iter = iter->next, count++) /* skip */;
+
+ return count;
+}
+
+
+/**
+ * Get the connectivity state of a tunnel.
+ *
+ * @param t Tunnel.
+ *
+ * @return Tunnel's connectivity state.
+ */
+enum CadetTunnel3CState
+GMT_get_cstate (struct CadetTunnel3 *t)
+{
+ if (NULL == t)
+ {
+ GNUNET_assert (0);
+ return (enum CadetTunnel3CState) -1;
+ }
+ return t->cstate;
+}
+
+
+/**
+ * Get the encryption state of a tunnel.
+ *
+ * @param t Tunnel.
+ *
+ * @return Tunnel's encryption state.
+ */
+enum CadetTunnel3EState
+GMT_get_estate (struct CadetTunnel3 *t)
+{
+ if (NULL == t)
+ {
+ GNUNET_assert (0);
+ return (enum CadetTunnel3EState) -1;
+ }
+ return t->estate;
+}
+
+/**
+ * Get the maximum buffer space for a tunnel towards a local client.
+ *
+ * @param t Tunnel.
+ *
+ * @return Biggest buffer space offered by any channel in the tunnel.
+ */
+unsigned int
+GMT_get_channels_buffer (struct CadetTunnel3 *t)
+{
+ struct CadetTChannel *iter;
+ unsigned int buffer;
+ unsigned int ch_buf;
+
+ if (NULL == t->channel_head)
+ {
+ /* Probably getting buffer for a channel create/handshake. */
+ return 64;
+ }
+
+ buffer = 0;
+ for (iter = t->channel_head; NULL != iter; iter = iter->next)
+ {
+ ch_buf = get_channel_buffer (iter);
+ if (ch_buf > buffer)
+ buffer = ch_buf;
+ }
+ return buffer;
+}
+
+
+/**
+ * Get the total buffer space for a tunnel for P2P traffic.
+ *
+ * @param t Tunnel.
+ *
+ * @return Buffer space offered by all connections in the tunnel.
+ */
+unsigned int
+GMT_get_connections_buffer (struct CadetTunnel3 *t)
+{
+ struct CadetTConnection *iter;
+ unsigned int buffer;
+
+ buffer = 0;
+ for (iter = t->connection_head; NULL != iter; iter = iter->next)
+ {
+ if (GMC_get_state (iter->c) != CADET_CONNECTION_READY)
+ {
+ continue;
+ }
+ buffer += get_connection_buffer (iter);
+ }
+
+ return buffer;
+}
+
+
+/**
+ * Get the tunnel's destination.
+ *
+ * @param t Tunnel.
+ *
+ * @return ID of the destination peer.
+ */
+const struct GNUNET_PeerIdentity *
+GMT_get_destination (struct CadetTunnel3 *t)
+{
+ return GMP_get_id (t->peer);
+}
+
+
+/**
+ * Get the tunnel's next free global channel ID.
+ *
+ * @param t Tunnel.
+ *
+ * @return GID of a channel free to use.
+ */
+CADET_ChannelNumber
+GMT_get_next_chid (struct CadetTunnel3 *t)
+{
+ CADET_ChannelNumber chid;
+ CADET_ChannelNumber mask;
+ int result;
+
+ /* Set bit 30 depending on the ID relationship. Bit 31 is always 0 for GID.
+ * If our ID is bigger or loopback tunnel, start at 0, bit 30 = 0
+ * If peer's ID is bigger, start at 0x4... bit 30 = 1
+ */
+ result = GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, GMP_get_id (t->peer));
+ if (0 > result)
+ mask = 0x40000000;
+ else
+ mask = 0x0;
+ t->next_chid |= mask;
+
+ while (NULL != GMT_get_channel (t, t->next_chid))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %u exists...\n", t->next_chid);
+ t->next_chid = (t->next_chid + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
+ t->next_chid |= mask;
+ }
+ chid = t->next_chid;
+ t->next_chid = (t->next_chid + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
+ t->next_chid |= mask;
+
+ return chid;
+}
+
+
+/**
+ * Send ACK on one or more channels due to buffer in connections.
+ *
+ * @param t Channel which has some free buffer space.
+ */
+void
+GMT_unchoke_channels (struct CadetTunnel3 *t)
+{
+ struct CadetTChannel *iter;
+ unsigned int buffer;
+ unsigned int channels = GMT_count_channels (t);
+ unsigned int choked_n;
+ struct CadetChannel *choked[channels];
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT_unchoke_channels on %s\n", GMT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " head: %p\n", t->channel_head);
+ if (NULL != t->channel_head)
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " head ch: %p\n", t->channel_head->ch);
+
+ /* Get buffer space */
+ buffer = GMT_get_connections_buffer (t);
+ if (0 == buffer)
+ {
+ return;
+ }
+
+ /* Count and remember choked channels */
+ choked_n = 0;
+ for (iter = t->channel_head; NULL != iter; iter = iter->next)
+ {
+ if (GNUNET_NO == get_channel_allowed (iter))
+ {
+ choked[choked_n++] = iter->ch;
+ }
+ }
+
+ /* Unchoke random channels */
+ while (0 < buffer && 0 < choked_n)
+ {
+ unsigned int r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+ choked_n);
+ GMCH_allow_client (choked[r], GMCH_is_origin (choked[r], GNUNET_YES));
+ choked_n--;
+ buffer--;
+ choked[r] = choked[choked_n];
+ }
+}
+
+
+/**
+ * Send ACK on one or more connections due to buffer space to the client.
+ *
+ * Iterates all connections of the tunnel and sends ACKs appropriately.
+ *
+ * @param t Tunnel.
+ */
+void
+GMT_send_connection_acks (struct CadetTunnel3 *t)
+{
+ struct CadetTConnection *iter;
+ uint32_t allowed;
+ uint32_t to_allow;
+ uint32_t allow_per_connection;
+ unsigned int cs;
+ unsigned int buffer;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel send connection ACKs on %s\n",
+ GMT_2s (t));
+
+ if (NULL == t)
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ buffer = GMT_get_channels_buffer (t);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer %u\n", buffer);
+
+ /* Count connections, how many messages are already allowed */
+ cs = GMT_count_connections (t);
+ for (allowed = 0, iter = t->connection_head; NULL != iter; iter = iter->next)
+ {
+ allowed += get_connection_allowed (iter);
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " allowed %u\n", allowed);
+
+ /* Make sure there is no overflow */
+ if (allowed > buffer)
+ {
+ return;
+ }
+
+ /* Authorize connections to send more data */
+ to_allow = buffer; /* - allowed; */
+
+ for (iter = t->connection_head;
+ NULL != iter && to_allow > 0;
+ iter = iter->next)
+ {
+ allow_per_connection = to_allow/cs;
+ to_allow -= allow_per_connection;
+ cs--;
+ if (get_connection_allowed (iter) > 64 / 3)
+ {
+ continue;
+ }
+ GMC_allow (iter->c, allow_per_connection,
+ GMC_is_origin (iter->c, GNUNET_NO));
+ }
+
+ GNUNET_break (to_allow == 0);
+}
+
+
+/**
+ * Cancel a previously sent message while it's in the queue.
+ *
+ * ONLY can be called before the continuation given to the send function
+ * is called. Once the continuation is called, the message is no longer in the
+ * queue.
+ *
+ * @param q Handle to the queue.
+ */
+void
+GMT_cancel (struct CadetTunnel3Queue *q)
+{
+ if (NULL != q->cq)
+ {
+ GMC_cancel (q->cq);
+ /* tun_message_sent() will be called and free q */
+ }
+ else if (NULL != q->tqd)
+ {
+ unqueue_data (q->tqd);
+ q->tqd = NULL;
+ if (NULL != q->cont)
+ q->cont (q->cont_cls, NULL, q, 0, 0);
+ GNUNET_free (q);
+ }
+ else
+ {
+ GNUNET_break (0);
+ }
+}
+
+
+/**
+ * Sends an already built message on a tunnel, encrypting it and
+ * choosing the best connection if not provided.
+ *
+ * @param message Message to send. Function modifies it.
+ * @param t Tunnel on which this message is transmitted.
+ * @param c Connection to use (autoselect if NULL).
+ * @param force Force the tunnel to take the message (buffer overfill).
+ * @param cont Continuation to call once message is really sent.
+ * @param cont_cls Closure for @c cont.
+ *
+ * @return Handle to cancel message. NULL if @c cont is NULL.
+ */
+struct CadetTunnel3Queue *
+GMT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
+ struct CadetTunnel3 *t, struct CadetConnection *c,
+ int force, GMT_sent cont, void *cont_cls)
+{
+ return send_prebuilt_message (message, t, c, force, cont, cont_cls, NULL);
+}
+
+
+/**
+ * Is the tunnel directed towards the local peer?
+ *
+ * @param t Tunnel.
+ *
+ * @return #GNUNET_YES if it is loopback.
+ */
+int
+GMT_is_loopback (const struct CadetTunnel3 *t)
+{
+ return (myid == GMP_get_short_id (t->peer));
+}
+
+
+/**
+ * Is the tunnel this path already?
+ *
+ * @param t Tunnel.
+ * @param p Path.
+ *
+ * @return #GNUNET_YES a connection uses this path.
+ */
+int
+GMT_is_path_used (const struct CadetTunnel3 *t, const struct CadetPeerPath *p)
+{
+ struct CadetTConnection *iter;
+
+ for (iter = t->connection_head; NULL != iter; iter = iter->next)
+ if (GMC_get_path (iter->c) == p)
+ return GNUNET_YES;
+
+ return GNUNET_NO;
+}
+
+
+/**
+ * Get a cost of a path for a tunnel considering existing connections.
+ *
+ * @param t Tunnel.
+ * @param path Candidate path.
+ *
+ * @return Cost of the path (path length + number of overlapping nodes)
+ */
+unsigned int
+GMT_get_path_cost (const struct CadetTunnel3 *t,
+ const struct CadetPeerPath *path)
+{
+ struct CadetTConnection *iter;
+ const struct CadetPeerPath *aux;
+ unsigned int overlap;
+ unsigned int i;
+ unsigned int j;
+
+ if (NULL == path)
+ return 0;
+
+ overlap = 0;
+ GNUNET_assert (NULL != t);
+
+ for (i = 0; i < path->length; i++)
+ {
+ for (iter = t->connection_head; NULL != iter; iter = iter->next)
+ {
+ aux = GMC_get_path (iter->c);
+ if (NULL == aux)
+ continue;
+
+ for (j = 0; j < aux->length; j++)
+ {
+ if (path->peers[i] == aux->peers[j])
+ {
+ overlap++;
+ break;
+ }
+ }
+ }
+ }
+ return path->length + overlap;
+}
+
+
+/**
+ * Get the static string for the peer this tunnel is directed.
+ *
+ * @param t Tunnel.
+ *
+ * @return Static string the destination peer's ID.
+ */
+const char *
+GMT_2s (const struct CadetTunnel3 *t)
+{
+ if (NULL == t)
+ return "(NULL)";
+
+ return GMP_2s (t->peer);
+}
+
+
+/******************************************************************************/
+/***************************** INFO/DEBUG
*******************************/
+/******************************************************************************/
+
+
+/**
+ * Log all possible info about the tunnel state to stderr.
+ *
+ * @param t Tunnel to debug.
+ */
+void
+GMT_debug (const struct CadetTunnel3 *t)
+{
+ struct CadetTChannel *iterch;
+ struct CadetTConnection *iterc;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT DEBUG TUNNEL TOWARDS %s\n", GMT_2s (t));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT cstate %s, estate %s\n",
+ cstate2s (t->cstate), estate2s (t->estate));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT kx_ctx %p, rekey_task %u\n",
+ t->kx_ctx, t->rekey_task);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT tq_head %p, tq_tail %p\n",
+ t->tq_head, t->tq_tail);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT destroy %u\n", t->destroy_task);
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT channels:\n");
+ for (iterch = t->channel_head; NULL != iterch; iterch = iterch->next)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT - %s\n", GMCH_2s (iterch->ch));
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT connections:\n");
+ for (iterc = t->connection_head; NULL != iterc; iterc = iterc->next)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT - %s [%u] buf: %u/%u (qn %u/%u)\n",
+ GMC_2s (iterc->c), GMC_get_state (iterc->c),
+ GMC_get_buffer (iterc->c, GNUNET_YES),
+ GMC_get_buffer (iterc->c, GNUNET_NO),
+ GMC_get_qn (iterc->c, GNUNET_YES),
+ GMC_get_qn (iterc->c, GNUNET_NO));
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT DEBUG TUNNEL END\n");
+}
+
+
+/**
+ * Iterate all tunnels.
+ *
+ * @param iter Iterator.
+ * @param cls Closure for @c iter.
+ */
+void
+GMT_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls)
+{
+ GNUNET_CONTAINER_multipeermap_iterate (tunnels, iter, cls);
+}
+
+
+/**
+ * Count all tunnels.
+ *
+ * @return Number of tunnels to remote peers kept by this peer.
+ */
+unsigned int
+GMT_count_all (void)
+{
+ return GNUNET_CONTAINER_multipeermap_size (tunnels);
+}
+
+
+/**
+ * Iterate all connections of a tunnel.
+ *
+ * @param t Tunnel whose connections to iterate.
+ * @param iter Iterator.
+ * @param cls Closure for @c iter.
+ */
+void
+GMT_iterate_connections (struct CadetTunnel3 *t, GMT_conn_iter iter, void *cls)
+{
+ struct CadetTConnection *ct;
+
+ for (ct = t->connection_head; NULL != ct; ct = ct->next)
+ iter (cls, ct->c);
+}
+
+
+/**
+ * Iterate all channels of a tunnel.
+ *
+ * @param t Tunnel whose channels to iterate.
+ * @param iter Iterator.
+ * @param cls Closure for @c iter.
+ */
+void
+GMT_iterate_channels (struct CadetTunnel3 *t, GMT_chan_iter iter, void *cls)
+{
+ struct CadetTChannel *cht;
+
+ for (cht = t->channel_head; NULL != cht; cht = cht->next)
+ iter (cls, cht->ch);
+}
Copied: gnunet/src/cadet/gnunet-service-cadet_tunnel.h (from rev 33185,
gnunet/src/mesh/gnunet-service-cadet_tunnel.h)
===================================================================
--- gnunet/src/cadet/gnunet-service-cadet_tunnel.h
(rev 0)
+++ gnunet/src/cadet/gnunet-service-cadet_tunnel.h 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -0,0 +1,531 @@
+/*
+ This file is part of GNUnet.
+ (C) 2013 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_tunnel.h
+ * @brief cadet service; dealing with tunnels and crypto
+ * @author Bartlomiej Polot
+ *
+ * All functions in this file should use the prefix GMT (Gnunet Cadet Tunnel)
+ */
+
+#ifndef GNUNET_SERVICE_CADET_TUNNEL_H
+#define GNUNET_SERVICE_CADET_TUNNEL_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0 /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+/**
+ * All the connectivity states a tunnel can be in.
+ */
+enum CadetTunnel3CState
+{
+ /**
+ * Uninitialized status, should never appear in operation.
+ */
+ CADET_TUNNEL3_NEW,
+
+ /**
+ * Path to the peer not known yet.
+ */
+ CADET_TUNNEL3_SEARCHING,
+
+ /**
+ * Request sent, not yet answered.
+ */
+ CADET_TUNNEL3_WAITING,
+
+ /**
+ * Peer connected and ready to accept data.
+ */
+ CADET_TUNNEL3_READY,
+
+ /**
+ * Tunnel being shut down, don't try to keep it alive.
+ */
+ CADET_TUNNEL3_SHUTDOWN
+};
+
+
+/**
+ * All the encryption states a tunnel can be in.
+ */
+enum CadetTunnel3EState
+{
+ /**
+ * Uninitialized status, should never appear in operation.
+ */
+ CADET_TUNNEL3_KEY_UNINITIALIZED,
+
+ /**
+ * Ephemeral key sent, waiting for peer's key.
+ */
+ CADET_TUNNEL3_KEY_SENT,
+
+ /**
+ * New ephemeral key and ping sent, waiting for pong.
+ * This means that we DO have the peer's ephemeral key, otherwise the
+ * state would be KEY_SENT.
+ */
+ CADET_TUNNEL3_KEY_PING,
+
+ /**
+ * Handshake completed: session key available.
+ */
+ CADET_TUNNEL3_KEY_OK,
+};
+
+/**
+ * Struct containing all information regarding a given peer
+ */
+struct CadetTunnel3;
+
+
+#include "gnunet-service-cadet_channel.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_peer.h"
+
+/**
+ * Handle for messages queued but not yet sent.
+ */
+struct CadetTunnel3Queue;
+
+/**
+ * Callback called when a queued message is sent.
+ *
+ * @param cls Closure.
+ * @param t Tunnel this message was on.
+ * @param type Type of message sent.
+ * @param size Size of the message.
+ */
+typedef void (*GMT_sent) (void *cls,
+ struct CadetTunnel3 *t,
+ struct CadetTunnel3Queue *q,
+ uint16_t type, size_t size);
+
+typedef void (*GMT_conn_iter) (void *cls, struct CadetConnection *c);
+typedef void (*GMT_chan_iter) (void *cls, struct CadetChannel *ch);
+
+
+/******************************************************************************/
+/******************************** API
***********************************/
+/******************************************************************************/
+
+/**
+ * Initialize tunnel subsystem.
+ *
+ * @param c Configuration handle.
+ * @param key ECC private key, to derive all other keys and do crypto.
+ */
+void
+GMT_init (const struct GNUNET_CONFIGURATION_Handle *c,
+ const struct GNUNET_CRYPTO_EddsaPrivateKey *key);
+
+/**
+ * Shut down the tunnel subsystem.
+ */
+void
+GMT_shutdown (void);
+
+/**
+ * Create a tunnel.
+ *
+ * @param destination Peer this tunnel is towards.
+ */
+struct CadetTunnel3 *
+GMT_new (struct CadetPeer *destination);
+
+/**
+ * Tunnel is empty: destroy it.
+ *
+ * Notifies all connections about the destruction.
+ *
+ * @param t Tunnel to destroy.
+ */
+void
+GMT_destroy_empty (struct CadetTunnel3 *t);
+
+/**
+ * Destroy tunnel if empty (no more channels).
+ *
+ * @param t Tunnel to destroy if empty.
+ */
+void
+GMT_destroy_if_empty (struct CadetTunnel3 *t);
+
+/**
+ * Destroy the tunnel.
+ *
+ * This function does not generate any warning traffic to clients or peers.
+ *
+ * Tasks:
+ * Cancel messages belonging to this tunnel queued to neighbors.
+ * Free any allocated resources linked to the tunnel.
+ *
+ * @param t The tunnel to destroy.
+ */
+void
+GMT_destroy (struct CadetTunnel3 *t);
+
+
+/**
+ * Change the tunnel's connection state.
+ *
+ * @param t Tunnel whose connection state to change.
+ * @param cstate New connection state.
+ */
+void
+GMT_change_cstate (struct CadetTunnel3* t, enum CadetTunnel3CState cstate);
+
+
+/**
+ * Change the tunnel encryption state.
+ *
+ * @param t Tunnel whose encryption state to change.
+ * @param state New encryption state.
+ */
+void
+GMT_change_estate (struct CadetTunnel3* t, enum CadetTunnel3EState state);
+
+/**
+ * Add a connection to a tunnel.
+ *
+ * @param t Tunnel.
+ * @param c Connection.
+ */
+void
+GMT_add_connection (struct CadetTunnel3 *t, struct CadetConnection *c);
+
+/**
+ * Mark a path as no longer valid for this tunnel: has been tried and failed.
+ *
+ * @param t Tunnel to update.
+ * @param path Invalid path to remove. Is destroyed after removal.
+ */
+void
+GMT_remove_path (struct CadetTunnel3 *t, struct CadetPeerPath *path);
+
+/**
+ * Remove a connection from a tunnel.
+ *
+ * @param t Tunnel.
+ * @param c Connection.
+ */
+void
+GMT_remove_connection (struct CadetTunnel3 *t, struct CadetConnection *c);
+
+/**
+ * Add a channel to a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel.
+ */
+void
+GMT_add_channel (struct CadetTunnel3 *t, struct CadetChannel *ch);
+
+/**
+ * Remove a channel from a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel.
+ */
+void
+GMT_remove_channel (struct CadetTunnel3 *t, struct CadetChannel *ch);
+
+/**
+ * Search for a channel by global ID.
+ *
+ * @param t Tunnel containing the channel.
+ * @param chid Public channel number.
+ *
+ * @return channel handler, NULL if doesn't exist
+ */
+struct CadetChannel *
+GMT_get_channel (struct CadetTunnel3 *t, CADET_ChannelNumber chid);
+
+/**
+ * Decrypt and demultiplex by message type. Call appropriate handler
+ * for a message
+ * towards a channel of a local tunnel.
+ *
+ * @param t Tunnel this message came on.
+ * @param msg Message header.
+ */
+void
+GMT_handle_encrypted (struct CadetTunnel3 *t,
+ const struct GNUNET_CADET_Encrypted *msg);
+
+/**
+ * Demultiplex an encapsulated KX message by message type.
+ *
+ * @param t Tunnel on which the message came.
+ * @param message KX message itself.
+ */
+void
+GMT_handle_kx (struct CadetTunnel3 *t,
+ const struct GNUNET_MessageHeader *message);
+
+/**
+ * @brief Use the given path for the tunnel.
+ * Update the next and prev hops (and RCs).
+ * (Re)start the path refresh in case the tunnel is locally owned.
+ *
+ * @param t Tunnel to update.
+ * @param p Path to use.
+ *
+ * @return Connection created.
+ */
+struct CadetConnection *
+GMT_use_path (struct CadetTunnel3 *t, struct CadetPeerPath *p);
+
+/**
+ * Count established (ready) connections of a tunnel.
+ *
+ * @param t Tunnel on which to count.
+ *
+ * @return Number of connections.
+ */
+unsigned int
+GMT_count_connections (struct CadetTunnel3 *t);
+
+/**
+ * Count channels of a tunnel.
+ *
+ * @param t Tunnel on which to count.
+ *
+ * @return Number of channels.
+ */
+unsigned int
+GMT_count_channels (struct CadetTunnel3 *t);
+
+/**
+ * Get the connectivity state of a tunnel.
+ *
+ * @param t Tunnel.
+ *
+ * @return Tunnel's connectivity state.
+ */
+enum CadetTunnel3CState
+GMT_get_cstate (struct CadetTunnel3 *t);
+
+/**
+ * Get the encryption state of a tunnel.
+ *
+ * @param t Tunnel.
+ *
+ * @return Tunnel's encryption state.
+ */
+enum CadetTunnel3EState
+GMT_get_estate (struct CadetTunnel3 *t);
+
+/**
+ * Get the maximum buffer space for a tunnel towards a local client.
+ *
+ * @param t Tunnel.
+ *
+ * @return Biggest buffer space offered by any channel in the tunnel.
+ */
+unsigned int
+GMT_get_channels_buffer (struct CadetTunnel3 *t);
+
+/**
+ * Get the total buffer space for a tunnel for P2P traffic.
+ *
+ * @param t Tunnel.
+ *
+ * @return Buffer space offered by all connections in the tunnel.
+ */
+unsigned int
+GMT_get_connections_buffer (struct CadetTunnel3 *t);
+
+/**
+ * Get the tunnel's destination.
+ *
+ * @param t Tunnel.
+ *
+ * @return ID of the destination peer.
+ */
+const struct GNUNET_PeerIdentity *
+GMT_get_destination (struct CadetTunnel3 *t);
+
+/**
+ * Get the tunnel's next free Channel ID.
+ *
+ * @param t Tunnel.
+ *
+ * @return ID of a channel free to use.
+ */
+CADET_ChannelNumber
+GMT_get_next_chid (struct CadetTunnel3 *t);
+
+/**
+ * Send ACK on one or more channels due to buffer in connections.
+ *
+ * @param t Channel which has some free buffer space.
+ */
+void
+GMT_unchoke_channels (struct CadetTunnel3 *t);
+
+/**
+ * Send ACK on one or more connections due to buffer space to the client.
+ *
+ * Iterates all connections of the tunnel and sends ACKs appropriately.
+ *
+ * @param t Tunnel which has some free buffer space.
+ */
+void
+GMT_send_connection_acks (struct CadetTunnel3 *t);
+
+/**
+ * Cancel a previously sent message while it's in the queue.
+ *
+ * ONLY can be called before the continuation given to the send function
+ * is called. Once the continuation is called, the message is no longer in the
+ * queue.
+ *
+ * @param q Handle to the queue.
+ */
+void
+GMT_cancel (struct CadetTunnel3Queue *q);
+
+/**
+ * Sends an already built message on a tunnel, encrypting it and
+ * choosing the best connection.
+ *
+ * @param message Message to send. Function modifies it.
+ * @param t Tunnel on which this message is transmitted.
+ * @param c Connection to use (autoselect if NULL).
+ * @param force Force the tunnel to take the message (buffer overfill).
+ * @param cont Continuation to call once message is really sent.
+ * @param cont_cls Closure for @c cont.
+ *
+ * @return Handle to cancel message. NULL if @c cont is NULL.
+ */
+struct CadetTunnel3Queue *
+GMT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
+ struct CadetTunnel3 *t, struct CadetConnection *c,
+ int force, GMT_sent cont, void *cont_cls);
+
+/**
+ * Is the tunnel directed towards the local peer?
+ *
+ * @param t Tunnel.
+ *
+ * @return #GNUNET_YES if it is loopback.
+ */
+int
+GMT_is_loopback (const struct CadetTunnel3 *t);
+
+/**
+ * Is the tunnel using this path already?
+ *
+ * @param t Tunnel.
+ * @param p Path.
+ *
+ * @return #GNUNET_YES a connection uses this path.
+ */
+int
+GMT_is_path_used (const struct CadetTunnel3 *t, const struct CadetPeerPath *p);
+
+/**
+ * Get a cost of a path for a tunnel considering existing connections.
+ *
+ * @param t Tunnel.
+ * @param path Candidate path.
+ *
+ * @return Cost of the path (path length + number of overlapping nodes)
+ */
+unsigned int
+GMT_get_path_cost (const struct CadetTunnel3 *t,
+ const struct CadetPeerPath *path);
+
+/**
+ * Get the static string for the peer this tunnel is directed.
+ *
+ * @param t Tunnel.
+ *
+ * @return Static string the destination peer's ID.
+ */
+const char *
+GMT_2s (const struct CadetTunnel3 *t);
+
+/**
+ * Log all possible info about the tunnel state.
+ *
+ * @param t Tunnel to debug.
+ */
+void
+GMT_debug (const struct CadetTunnel3 *t);
+
+/**
+ * Iterate all tunnels.
+ *
+ * @param iter Iterator.
+ * @param cls Closure for @c iter.
+ */
+void
+GMT_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls);
+
+/**
+ * Count all tunnels.
+ *
+ * @return Number of tunnels to remote peers kept by this peer.
+ */
+unsigned int
+GMT_count_all (void);
+
+/**
+ * Iterate all connections of a tunnel.
+ *
+ * @param t Tunnel whose connections to iterate.
+ * @param iter Iterator.
+ * @param cls Closure for @c iter.
+ */
+void
+GMT_iterate_connections (struct CadetTunnel3 *t, GMT_conn_iter iter, void
*cls);
+
+/**
+ * Iterate all channels of a tunnel.
+ *
+ * @param t Tunnel whose channels to iterate.
+ * @param iter Iterator.
+ * @param cls Closure for @c iter.
+ */
+void
+GMT_iterate_channels (struct CadetTunnel3 *t, GMT_chan_iter iter, void *cls);
+
+#if 0 /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* ifndef GNUNET_CADET_SERVICE_TUNNEL_H */
+#endif
+/* end of gnunet-cadet-service_tunnel.h */
Copied: gnunet/src/cadet/loopcheck.sh (from rev 33185,
gnunet/src/mesh/loopcheck.sh)
===================================================================
--- gnunet/src/cadet/loopcheck.sh (rev 0)
+++ gnunet/src/cadet/loopcheck.sh 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+while true; do
+ date;
+ taskset 1 make check || break;
+ grep -B 10 Assert *log && break
+ ls core* &> /dev/null && break
+done
Copied: gnunet/src/cadet/mesh.conf.in (from rev 33185,
gnunet/src/mesh/mesh.conf.in)
===================================================================
--- gnunet/src/cadet/mesh.conf.in (rev 0)
+++ gnunet/src/cadet/mesh.conf.in 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,21 @@
+[mesh]
+AUTOSTART = @AUTOSTART@
address@hidden@PORT = 2096
+HOSTNAME = localhost
+BINARY = gnunet-service-mesh
+ACCEPT_FROM = 127.0.0.1;
+ACCEPT_FROM6 = ::1;
+UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-mesh.sock
+UNIX_MATCH_UID = YES
+UNIX_MATCH_GID = YES
+REFRESH_CONNECTION_TIME = 5 min
+ID_ANNOUNCE_TIME = 1 h
+APP_ANNOUNCE_TIME = 1 h
+CONNECT_TIMEOUT = 30 s
+DEFAULT_TTL = 64
+DHT_REPLICATION_LEVEL = 3
+MAX_TUNNELS = 1000
+# MAX_TUNNELS deprecated
+MAX_CONNECTIONS = 1000
+MAX_MSGS_QUEUE = 10000
+MAX_PEERS = 1000
Copied: gnunet/src/cadet/profiler.conf (from rev 33185,
gnunet/src/mesh/profiler.conf)
===================================================================
--- gnunet/src/cadet/profiler.conf (rev 0)
+++ gnunet/src/cadet/profiler.conf 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,19 @@
address@hidden@ test_mesh.conf
+
+[testbed]
+OVERLAY_TOPOLOGY = RANDOM
+OVERLAY_RANDOM_LINKS = %LINKS%
+MAX_PARALLEL_SERVICE_CONNECTIONS=4000
+SETUP_TIMEOUT = 60 m
+
+[transport]
+#MANIPULATE_DELAY_IN = 50 ms
+MANIPULATE_DELAY_OUT = 10 ms
+
+[mesh]
+REFRESH_CONNECTION_TIME = 1 h
+DISABLE_TRY_CONNECT = YES
+ID_ANNOUNCE_TIME = 240 s
+
+[dht]
+FORCE_NSE = %NSE%
Copied: gnunet/src/cadet/run_profiler.sh (from rev 33185,
gnunet/src/mesh/run_profiler.sh)
===================================================================
--- gnunet/src/cadet/run_profiler.sh (rev 0)
+++ gnunet/src/cadet/run_profiler.sh 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+if [ "$#" -lt "3" ]; then
+ echo "usage: $0 ROUND_TIME PEERS PINGING_PEERS";
+ echo "example: $0 30s 16 1";
+ exit 1;
+fi
+
+ROUNDTIME=$1
+PEERS=$2
+PINGS=$3
+
+if [ $PEERS -eq 1 ]; then
+ echo "cannot run 1 peer";
+ exit 1;
+fi
+
+LINKS=`echo "l($PEERS)/l(2) * $PEERS" | bc -l`
+LINKS=`printf "%.0f" $LINKS`
+NSE=`echo "l($PEERS)/l(2)" | bc -l`
+echo "using $PEERS peers, $LINKS links";
+
+sed -e "s/%LINKS%/$LINKS/;s/%NSE%/$NSE/" profiler.conf > .profiler.conf
+
+./gnunet-mesh-profiler $ROUNDTIME $PEERS $PINGS $4 |& tee log | grep -v DEBUG
Copied: gnunet/src/cadet/small.dat (from rev 33185, gnunet/src/mesh/small.dat)
===================================================================
--- gnunet/src/cadet/small.dat (rev 0)
+++ gnunet/src/cadet/small.dat 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,21 @@
+16
+1:2
+1:9
+2:3
+3:4
+3:11
+4:5
+5:6
+5:13
+6:7
+7:8
+7:15
+8:9
+9:10
+10:11
+11:12
+12:13
+13:14
+14:15
+15:16
+16:1
Copied: gnunet/src/cadet/test_cadet.c (from rev 33185,
gnunet/src/mesh/test_cadet.c)
===================================================================
--- gnunet/src/cadet/test_cadet.c (rev 0)
+++ gnunet/src/cadet/test_cadet.c 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,953 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file cadet/test_cadet.c
+ *
+ * @brief Test for the cadet service: retransmission of traffic.
+ */
+#include <stdio.h>
+#include "platform.h"
+#include "cadet_test_lib.h"
+#include "gnunet_cadet_service.h"
+#include "gnunet_statistics_service.h"
+#include <gauger.h>
+
+
+/**
+ * How namy messages to send
+ */
+#define TOTAL_PACKETS 100
+
+/**
+ * How long until we give up on connecting the peers?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
+
+/**
+ * Time to wait for stuff that should be rather fast
+ */
+#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
+
+/**
+ * DIFFERENT TESTS TO RUN
+ */
+#define SETUP 0
+#define FORWARD 1
+#define KEEPALIVE 2
+#define SPEED 3
+#define SPEED_ACK 4
+#define SPEED_REL 8
+#define P2P_SIGNAL 10
+
+/**
+ * Which test are we running?
+ */
+static int test;
+
+/**
+ * String with test name
+ */
+char *test_name;
+
+/**
+ * Flag to send traffic leaf->root in speed tests to test BCK_ACK logic.
+ */
+static int test_backwards = GNUNET_NO;
+
+/**
+ * How many events have happened
+ */
+static int ok;
+
+/**
+ * Number of events expected to conclude the test successfully.
+ */
+int ok_goal;
+
+/**
+ * Size of each test packet
+ */
+size_t size_payload = sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t);
+
+/**
+ * Operation to get peer ids.
+ */
+struct GNUNET_TESTBED_Operation *t_op[2];
+
+/**
+ * Peer ids.
+ */
+struct GNUNET_PeerIdentity *p_id[2];
+
+/**
+ * Peer ids counter.
+ */
+unsigned int p_ids;
+
+/**
+ * Is the setup initialized?
+ */
+static int initialized;
+
+/**
+ * Number of payload packes sent
+ */
+static int data_sent;
+
+/**
+ * Number of payload packets received
+ */
+static int data_received;
+
+/**
+ * Number of payload packed explicitly (app level) acknowledged
+ */
+static int data_ack;
+
+/**
+ * Total number of currently running peers.
+ */
+static unsigned long long peers_running;
+
+/**
+ * Test context (to shut down).
+ */
+struct GNUNET_CADET_TEST_Context *test_ctx;
+
+/**
+ * Task called to disconnect peers.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
+
+/**
+ * Task To perform tests
+ */
+static GNUNET_SCHEDULER_TaskIdentifier test_task;
+
+/**
+ * Task called to shutdown test.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle;
+
+/**
+ * Cadet handle for the root peer
+ */
+static struct GNUNET_CADET_Handle *h1;
+
+/**
+ * Cadet handle for the first leaf peer
+ */
+static struct GNUNET_CADET_Handle *h2;
+
+/**
+ * Channel handle for the root peer
+ */
+static struct GNUNET_CADET_Channel *ch;
+
+/**
+ * Channel handle for the dest peer
+ */
+static struct GNUNET_CADET_Channel *incoming_ch;
+
+/**
+ * Time we started the data transmission (after channel has been established
+ * and initilized).
+ */
+static struct GNUNET_TIME_Absolute start_time;
+
+/**
+ * Peers handle.
+ */
+static struct GNUNET_TESTBED_Peer **testbed_peers;
+
+/**
+ * Statistics operation handle.
+ */
+static struct GNUNET_TESTBED_Operation *stats_op;
+
+/**
+ * Keepalives sent.
+ */
+static unsigned int ka_sent;
+
+/**
+ * Keepalives received.
+ */
+static unsigned int ka_received;
+
+
+/**
+ * Show the results of the test (banwidth acheived) and log them to GAUGER
+ */
+static void
+show_end_data (void)
+{
+ static struct GNUNET_TIME_Absolute end_time;
+ static struct GNUNET_TIME_Relative total_time;
+
+ end_time = GNUNET_TIME_absolute_get();
+ total_time = GNUNET_TIME_absolute_get_difference(start_time, end_time);
+ FPRINTF (stderr, "\nResults of test \"%s\"\n", test_name);
+ FPRINTF (stderr, "Test time %s\n",
+ GNUNET_STRINGS_relative_time_to_string (total_time,
+ GNUNET_YES));
+ FPRINTF (stderr, "Test bandwidth: %f kb/s\n",
+ 4 * TOTAL_PACKETS * 1.0 / (total_time.rel_value_us / 1000)); //
4bytes * ms
+ FPRINTF (stderr, "Test throughput: %f packets/s\n\n",
+ TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000)); //
packets * ms
+ GAUGER ("CADET", test_name,
+ TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000),
+ "packets/s");
+}
+
+
+/**
+ * Shut down peergroup, clean up.
+ *
+ * @param cls Closure (unused).
+ * @param tc Task Context.
+ */
+static void
+shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n");
+ shutdown_handle = GNUNET_SCHEDULER_NO_TASK;
+}
+
+
+/**
+ * Disconnect from cadet services af all peers, call shutdown.
+ *
+ * @param cls Closure (unused).
+ * @param tc Task Context.
+ */
+static void
+disconnect_cadet_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext
*tc)
+{
+ long line = (long) cls;
+ unsigned int i;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "disconnecting cadet service of peers, called from line %ld\n",
+ line);
+ disconnect_task = GNUNET_SCHEDULER_NO_TASK;
+ for (i = 0; i < 2; i++)
+ {
+ GNUNET_TESTBED_operation_done (t_op[i]);
+ }
+ if (NULL != ch)
+ {
+ GNUNET_CADET_channel_destroy (ch);
+ ch = NULL;
+ }
+ if (NULL != incoming_ch)
+ {
+ GNUNET_CADET_channel_destroy (incoming_ch);
+ incoming_ch = NULL;
+ }
+ GNUNET_CADET_TEST_cleanup (test_ctx);
+ if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle)
+ {
+ GNUNET_SCHEDULER_cancel (shutdown_handle);
+ }
+ shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
+}
+
+
+/**
+ * Abort test: schedule disconnect and shutdown immediately
+ *
+ * @param line Line in the code the abort is requested from (__LINE__).
+ */
+static void
+abort_test (long line)
+{
+ if (disconnect_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (disconnect_task);
+ disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
+ (void *) line);
+ }
+}
+
+/**
+ * Transmit ready callback.
+ *
+ * @param cls Closure (message type).
+ * @param size Size of the tranmist buffer.
+ * @param buf Pointer to the beginning of the buffer.
+ *
+ * @return Number of bytes written to buf.
+ */
+static size_t
+tmt_rdy (void *cls, size_t size, void *buf);
+
+
+/**
+ * Task to schedule a new data transmission.
+ *
+ * @param cls Closure (peer #).
+ * @param tc Task Context.
+ */
+static void
+data_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_CADET_TransmitHandle *th;
+ struct GNUNET_CADET_Channel *channel;
+
+ if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
+ return;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data task\n");
+ if (GNUNET_YES == test_backwards)
+ {
+ channel = incoming_ch;
+ }
+ else
+ {
+ channel = ch;
+ }
+ th = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ size_payload, &tmt_rdy, (void *) 1L);
+ if (NULL == th)
+ {
+ unsigned long i = (unsigned long) cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Retransmission\n");
+ if (0 == i)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, " in 1 ms\n");
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
+ &data_task, (void *)1UL);
+ }
+ else
+ {
+ i++;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "in %u ms\n", i);
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(
+ GNUNET_TIME_UNIT_MILLISECONDS,
+ i),
+ &data_task, (void *)i);
+ }
+ }
+}
+
+
+/**
+ * Transmit ready callback
+ *
+ * @param cls Closure (message type).
+ * @param size Size of the buffer we have.
+ * @param buf Buffer to copy data to.
+ */
+size_t
+tmt_rdy (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_MessageHeader *msg = buf;
+ uint32_t *data;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "tmt_rdy called, filling buffer\n");
+ if (size < size_payload || NULL == buf)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "size %u, buf %p, data_sent %u, data_received %u\n",
+ size, buf, data_sent, data_received);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ok %u, ok goal %u\n", ok, ok_goal);
+ GNUNET_break (ok >= ok_goal - 2);
+
+ return 0;
+ }
+ msg->size = htons (size);
+ msg->type = htons ((long) cls);
+ data = (uint32_t *) &msg[1];
+ *data = htonl (data_sent);
+ if (GNUNET_NO == initialized)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "sending initializer\n");
+ }
+ else if (SPEED == test)
+ {
+ data_sent++;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ " Sent packet %d\n", data_sent);
+ if (data_sent < TOTAL_PACKETS)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ " Scheduling packet %d\n", data_sent + 1);
+ GNUNET_SCHEDULER_add_now (&data_task, NULL);
+ }
+ }
+
+ return size_payload;
+}
+
+
+/**
+ * Function is called whenever a message is received.
+ *
+ * @param cls closure (set from GNUNET_CADET_connect)
+ * @param channel connection to the other end
+ * @param channel_ctx place to store local state associated with the channel
+ * @param message the actual message
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+int
+data_callback (void *cls, struct GNUNET_CADET_Channel *channel,
+ void **channel_ctx,
+ const struct GNUNET_MessageHeader *message)
+{
+ long client = (long) cls;
+ long expected_target_client;
+ uint32_t *data;
+
+ ok++;
+
+ GNUNET_CADET_receive_done (channel);
+
+ if ((ok % 20) == 0)
+ {
+ if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
+ {
+ GNUNET_SCHEDULER_cancel (disconnect_task);
+ disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
+ &disconnect_cadet_peers,
+ (void *) __LINE__);
+ }
+ }
+
+ switch (client)
+ {
+ case 0L:
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message!\n");
+ break;
+ case 4L:
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Leaf client %li got a message.\n",
+ client);
+ break;
+ default:
+ GNUNET_assert (0);
+ break;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: (%d/%d)\n", ok, ok_goal);
+ data = (uint32_t *) &message[1];
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, " payload: (%u)\n", ntohl (*data));
+ if (SPEED == test && GNUNET_YES == test_backwards)
+ {
+ expected_target_client = 0L;
+ }
+ else
+ {
+ expected_target_client = 4L;
+ }
+
+ if (GNUNET_NO == initialized)
+ {
+ initialized = GNUNET_YES;
+ start_time = GNUNET_TIME_absolute_get ();
+ if (SPEED == test)
+ {
+ GNUNET_assert (4L == client);
+ GNUNET_SCHEDULER_add_now (&data_task, NULL);
+ return GNUNET_OK;
+ }
+ }
+
+ if (client == expected_target_client) // Normally 4
+ {
+ data_received++;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received data %u\n", data_received);
+ if (SPEED != test || (ok_goal - 2) == ok)
+ {
+ GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ size_payload, &tmt_rdy, (void *) 1L);
+ return GNUNET_OK;
+ }
+ else
+ {
+ if (data_received < TOTAL_PACKETS)
+ return GNUNET_OK;
+ }
+ }
+ else // Normally 0
+ {
+ if (test == SPEED_ACK || test == SPEED)
+ {
+ data_ack++;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received ack %u\n", data_ack);
+ GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ size_payload, &tmt_rdy, (void *) 1L);
+ if (data_ack < TOTAL_PACKETS && SPEED != test)
+ return GNUNET_OK;
+ if (ok == 2 && SPEED == test)
+ return GNUNET_OK;
+ show_end_data();
+ }
+ if (test == P2P_SIGNAL)
+ {
+ GNUNET_CADET_channel_destroy (incoming_ch);
+ incoming_ch = NULL;
+ }
+ else
+ {
+ GNUNET_CADET_channel_destroy (ch);
+ ch = NULL;
+ }
+ }
+
+ if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
+ {
+ GNUNET_SCHEDULER_cancel (disconnect_task);
+ disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
+ &disconnect_cadet_peers,
+ (void *) __LINE__);
+ }
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Stats callback. Finish the stats testbed operation and when all stats have
+ * been iterated, shutdown the test.
+ *
+ * @param cls closure
+ * @param op the operation that has been finished
+ * @param emsg error message in case the operation has failed; will be NULL if
+ * operation has executed successfully.
+ */
+static void
+stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "stats_cont for peer %u\n", cls);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, " sent: %u, received: %u\n",
+ ka_sent, ka_received);
+ if (ka_sent < 2 || ka_sent > ka_received + 1)
+ ok--;
+ GNUNET_TESTBED_operation_done (stats_op);
+
+ if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
+ GNUNET_SCHEDULER_cancel (disconnect_task);
+ disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
+ (void *) __LINE__);
+
+}
+
+
+/**
+ * Process statistic values.
+ *
+ * @param cls closure
+ * @param peer the peer the statistic belong to
+ * @param subsystem name of subsystem that created the statistic
+ * @param name the name of the datum
+ * @param value the current value
+ * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
+ * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
+ */
+static int
+stats_iterator (void *cls, const struct GNUNET_TESTBED_Peer *peer,
+ const char *subsystem, const char *name,
+ uint64_t value, int is_persistent)
+{
+ static const char *s_sent = "# keepalives sent";
+ static const char *s_recv = "# keepalives received";
+ uint32_t i;
+
+ i = GNUNET_TESTBED_get_index (peer);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %u - %s [%s]: %llu\n",
+ i, subsystem, name, value);
+ if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i)
+ ka_sent = value;
+
+ if (0 == strncmp(s_recv, name, strlen (s_recv)) && 4 == i)
+ ka_received = value;
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Task check that keepalives were sent and received.
+ *
+ * @param cls Closure (NULL).
+ * @param tc Task Context.
+ */
+static void
+check_keepalives (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
+ return;
+
+ disconnect_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "check keepalives\n");
+ GNUNET_CADET_channel_destroy (ch);
+ stats_op = GNUNET_TESTBED_get_statistics (5, testbed_peers,
+ "cadet", NULL,
+ stats_iterator, stats_cont, NULL);
+}
+
+
+/**
+ * Handlers, for diverse services
+ */
+static struct GNUNET_CADET_MessageHandler handlers[] = {
+ {&data_callback, 1, sizeof (struct GNUNET_MessageHeader)},
+ {NULL, 0, 0}
+};
+
+
+/**
+ * Method called whenever another peer has added us to a channel
+ * the other peer initiated.
+ *
+ * @param cls Closure.
+ * @param channel New handle to the channel.
+ * @param initiator Peer that started the channel.
+ * @param port Port this channel is connected to.
+ * @param options channel option flags
+ * @return Initial channel context for the channel
+ * (can be NULL -- that's not an error).
+ */
+static void *
+incoming_channel (void *cls, struct GNUNET_CADET_Channel *channel,
+ const struct GNUNET_PeerIdentity *initiator,
+ uint32_t port, enum GNUNET_CADET_ChannelOption options)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Incoming channel from %s to peer %d\n",
+ GNUNET_i2s (initiator), (long) cls);
+ ok++;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
+ if ((long) cls == 4L)
+ incoming_ch = channel;
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Incoming channel for unknown client %lu\n", (long) cls);
+ GNUNET_break(0);
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
+ {
+ GNUNET_SCHEDULER_cancel (disconnect_task);
+ if (KEEPALIVE == test)
+ {
+ struct GNUNET_TIME_Relative delay;
+ delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS , 5);
+ disconnect_task =
+ GNUNET_SCHEDULER_add_delayed (delay, &check_keepalives, NULL);
+ }
+ else
+ disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
+ &disconnect_cadet_peers,
+ (void *) __LINE__);
+ }
+
+ return NULL;
+}
+
+/**
+ * Function called whenever an inbound channel is destroyed. Should clean up
+ * any associated state.
+ *
+ * @param cls closure (set from GNUNET_CADET_connect)
+ * @param channel connection to the other end (henceforth invalid)
+ * @param channel_ctx place where local state associated
+ * with the channel is stored
+ */
+static void
+channel_cleaner (void *cls, const struct GNUNET_CADET_Channel *channel,
+ void *channel_ctx)
+{
+ long i = (long) cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Incoming channel disconnected at peer %ld\n", i);
+ if (4L == i)
+ {
+ ok++;
+ GNUNET_break (channel == incoming_ch);
+ incoming_ch = NULL;
+ }
+ else if (0L == i)
+ {
+ if (P2P_SIGNAL == test)
+ {
+ ok ++;
+ }
+ GNUNET_break (channel == ch);
+ ch = NULL;
+ }
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Unknown peer! %d\n", i);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
+
+ if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
+ {
+ GNUNET_SCHEDULER_cancel (disconnect_task);
+ disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
+ (void *) __LINE__);
+ }
+
+ return;
+}
+
+
+/**
+ * START THE TESTCASE ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES.
+ *
+ * Testcase continues when the root receives confirmation of connected peers,
+ * on callback funtion ch.
+ *
+ * @param cls Closure (unsued).
+ * @param tc Task Context.
+ */
+static void
+do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ enum GNUNET_CADET_ChannelOption flags;
+
+ if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
+ return;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test_task\n");
+
+ if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
+ {
+ GNUNET_SCHEDULER_cancel (disconnect_task);
+ }
+
+ flags = GNUNET_CADET_OPTION_DEFAULT;
+ if (SPEED_REL == test)
+ {
+ test = SPEED;
+ flags |= GNUNET_CADET_OPTION_RELIABLE;
+ }
+ ch = GNUNET_CADET_channel_create (h1, NULL, p_id[1], 1, flags);
+
+ disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
+ &disconnect_cadet_peers,
+ (void *) __LINE__);
+ if (KEEPALIVE == test)
+ return; /* Don't send any data. */
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending data initializer...\n");
+ data_ack = 0;
+ data_received = 0;
+ data_sent = 0;
+ GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ size_payload, &tmt_rdy, (void *) 1L);
+}
+
+/**
+ * Callback to be called when the requested peer information is available
+ *
+ * @param cls the closure from GNUNET_TESTBED_peer_get_information()
+ * @param op the operation this callback corresponds to
+ * @param pinfo the result; will be NULL if the operation has failed
+ * @param emsg error message if the operation has failed;
+ * NULL if the operation is successfull
+ */
+static void
+pi_cb (void *cls,
+ struct GNUNET_TESTBED_Operation *op,
+ const struct GNUNET_TESTBED_PeerInformation *pinfo,
+ const char *emsg)
+{
+ long i = (long) cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "id callback for %ld\n", i);
+
+ if (NULL == pinfo || NULL != emsg)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg);
+ abort_test (__LINE__);
+ return;
+ }
+ p_id[i] = pinfo->result.id;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " id: %s\n", GNUNET_i2s (p_id[i]));
+ p_ids++;
+ if (p_ids < 2)
+ return;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n");
+ test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+ &do_test, NULL);
+}
+
+/**
+ * test main: start test when all peers are connected
+ *
+ * @param cls Closure.
+ * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
+ * @param num_peers Number of peers that are running.
+ * @param peers Array of peers.
+ * @param cadetes Handle to each of the CADETs of the peers.
+ */
+static void
+tmain (void *cls,
+ struct GNUNET_CADET_TEST_Context *ctx,
+ unsigned int num_peers,
+ struct GNUNET_TESTBED_Peer **peers,
+ struct GNUNET_CADET_Handle **cadetes)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n");
+ ok = 0;
+ test_ctx = ctx;
+ peers_running = num_peers;
+ testbed_peers = peers;
+ h1 = cadetes[0];
+ h2 = cadetes[num_peers - 1];
+ disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
+ &disconnect_cadet_peers,
+ (void *) __LINE__);
+ shutdown_handle = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ &shutdown_task, NULL);
+ t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0],
+ GNUNET_TESTBED_PIT_IDENTITY,
+ &pi_cb, (void *) 0L);
+ t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1],
+ GNUNET_TESTBED_PIT_IDENTITY,
+ &pi_cb, (void *) 1L);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n");
+}
+
+
+/**
+ * Main: start test
+ */
+int
+main (int argc, char *argv[])
+{
+ initialized = GNUNET_NO;
+ static uint32_t ports[2];
+ const char *config_file;
+
+ GNUNET_log_setup ("test", "DEBUG", NULL);
+ config_file = "test_cadet.conf";
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start\n");
+ if (strstr (argv[0], "_cadet_forward") != NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "FORWARD\n");
+ test = FORWARD;
+ test_name = "unicast";
+ ok_goal = 4;
+ }
+ else if (strstr (argv[0], "_cadet_signal") != NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SIGNAL\n");
+ test = P2P_SIGNAL;
+ test_name = "signal";
+ ok_goal = 4;
+ }
+ else if (strstr (argv[0], "_cadet_speed_ack") != NULL)
+ {
+ /* Test is supposed to generate the following callbacks:
+ * 1 incoming channel (@dest)
+ * TOTAL_PACKETS received data packet (@dest)
+ * TOTAL_PACKETS received data packet (@orig)
+ * 1 received channel destroy (@dest)
+ */
+ ok_goal = TOTAL_PACKETS * 2 + 2;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n");
+ test = SPEED_ACK;
+ test_name = "speed ack";
+ }
+ else if (strstr (argv[0], "_cadet_speed") != NULL)
+ {
+ /* Test is supposed to generate the following callbacks:
+ * 1 incoming channel (@dest)
+ * 1 initial packet (@dest)
+ * TOTAL_PACKETS received data packet (@dest)
+ * 1 received data packet (@orig)
+ * 1 received channel destroy (@dest)
+ */
+ ok_goal = TOTAL_PACKETS + 4;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n");
+ if (strstr (argv[0], "_reliable") != NULL)
+ {
+ test = SPEED_REL;
+ test_name = "speed reliable";
+ config_file = "test_cadet_drop.conf";
+ }
+ else
+ {
+ test = SPEED;
+ test_name = "speed";
+ }
+ }
+ else if (strstr (argv[0], "_keepalive") != NULL)
+ {
+ test = KEEPALIVE;
+ /* Test is supposed to generate the following callbacks:
+ * 1 incoming channel (@dest)
+ * [wait]
+ * 1 received channel destroy (@dest)
+ */
+ ok_goal = 2;
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNKNOWN\n");
+ test = SETUP;
+ ok_goal = 0;
+ }
+
+ if (strstr (argv[0], "backwards") != NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "BACKWARDS (LEAF TO ROOT)\n");
+ test_backwards = GNUNET_YES;
+ GNUNET_asprintf (&test_name, "backwards %s", test_name);
+ }
+
+ p_ids = 0;
+ ports[0] = 1;
+ ports[1] = 0;
+ GNUNET_CADET_TEST_run ("test_cadet_small",
+ config_file,
+ 5,
+ &tmain,
+ NULL, /* tmain cls */
+ &incoming_channel,
+ &channel_cleaner,
+ handlers,
+ ports);
+
+ if (ok_goal > ok)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "FAILED! (%d/%d)\n", ok, ok_goal);
+ return 1;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n");
+ return 0;
+}
+
+/* end of test_cadet.c */
+
Copied: gnunet/src/cadet/test_cadet.conf (from rev 33185,
gnunet/src/mesh/test_cadet.conf)
===================================================================
--- gnunet/src/cadet/test_cadet.conf (rev 0)
+++ gnunet/src/cadet/test_cadet.conf 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,100 @@
+[testbed]
+AUTOSTART = NO
+PORT = 12113
+ACCEPT_FROM = 127.0.0.1;
+HOSTNAME = localhost
+OVERLAY_TOPOLOGY = LINE
+#PREFIX = xterm -geometry 100x85 -T peer1 -e libtool --mode=execute gdb --args
+
+[fs]
+AUTOSTART = NO
+
+[resolver]
+AUTOSTART = NO
+
+[mesh]
+#BINARY = gnunet-service-mesh-enc
+#PREFIX = valgrind --leak-check=full
+#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
+AUTOSTART = NO
+ACCEPT_FROM = 127.0.0.1;
+REFRESH_CONNECTION_TIME = 2 s
+ID_ANNOUNCE_TIME = 5 s
+CONNECT_TIMEOUT = 30 s
+DEFAULT_TTL = 16
+DHT_REPLICATION_LEVEL = 10
+MAX_TUNNELS = 10
+MAX_CONNECTIONS = 10
+MAX_MSGS_QUEUE = 20
+DISABLE_TRY_CONNECT = YES
+
+[dht]
+AUTOSTART = NO
+DISABLE_TRY_CONNECT = YES
+FORCE_NSE = 3
+
+[dhtcache]
+QUOTA = 1 MB
+DATABASE = heap
+
+[transport]
+PLUGINS = udp
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+NEIGHBOUR_LIMIT = 50
+PORT = 12365
+#MANIPULATE_DELAY_IN = 10 ms
+#MANIPULATE_DELAY_OUT = 10 ms
+
+
+[ats]
+WAN_QUOTA_OUT = 3932160
+WAN_QUOTA_IN = 3932160
+
+[core]
+PORT = 12092
+AUTOSTART = YES
+USE_EPHEMERAL_KEYS = NO
+
+[arm]
+DEFAULTSERVICES = core transport dht mesh statistics
+PORT = 12366
+
+[transport-udp]
+TIMEOUT = 300 s
+PORT = 12368
+
+[gnunetd]
+HOSTKEY = $GNUNET_TEST_HOME/.hostkey
+
+[PATHS]
+GNUNET_TEST_HOME = /tmp/test-mesh/
+
+[dns]
+AUTOSTART = NO
+
+[nse]
+AUTOSTART = NO
+
+[vpn]
+AUTOSTART = NO
+
+[nat]
+RETURN_LOCAL_ADDRESSES = YES
+DISABLEV6 = YES
+USE_LOCALADDR = YES
+
+[gns-helper-service-w32]
+AUTOSTART = NO
+
+[consensus]
+AUTOSTART = NO
+
+[gns]
+AUTOSTART = NO
+
+[statistics]
+AUTOSTART = NO
+
+[peerinfo]
+NO_IO = YES
Copied: gnunet/src/cadet/test_cadet_drop.conf (from rev 33185,
gnunet/src/mesh/test_cadet_drop.conf)
===================================================================
--- gnunet/src/cadet/test_cadet_drop.conf (rev 0)
+++ gnunet/src/cadet/test_cadet_drop.conf 2014-05-07 12:07:16 UTC (rev
33186)
@@ -0,0 +1,4 @@
address@hidden@ test_mesh.conf
+
+[mesh]
+DROP_PERCENT = 1
Copied: gnunet/src/cadet/test_cadet_local.c (from rev 33185,
gnunet/src/mesh/test_cadet_local.c)
===================================================================
--- gnunet/src/cadet/test_cadet_local.c (rev 0)
+++ gnunet/src/cadet/test_cadet_local.c 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,337 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file cadet/test_cadet_local.c
+ * @brief test cadet local: test of cadet channels with just one peer
+ * @author Bartlomiej Polot
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_dht_service.h"
+#include "gnunet_testing_lib.h"
+#include "gnunet_cadet_service.h"
+
+struct GNUNET_TESTING_Peer *me;
+
+static struct GNUNET_CADET_Handle *cadet_peer_1;
+
+static struct GNUNET_CADET_Handle *cadet_peer_2;
+
+static struct GNUNET_CADET_Channel *ch;
+
+static int result = GNUNET_OK;
+
+static int got_data = GNUNET_NO;
+
+static GNUNET_SCHEDULER_TaskIdentifier abort_task;
+
+static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
+
+static struct GNUNET_CADET_TransmitHandle *mth;
+
+
+/**
+ * Connect to other client and send data
+ *
+ * @param cls Closue (unused).
+ * @param tc TaskContext.
+ */
+static void
+do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Shutdown nicely
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutdown\n");
+ if (GNUNET_SCHEDULER_NO_TASK != abort_task)
+ {
+ GNUNET_SCHEDULER_cancel (abort_task);
+ }
+ if (NULL != ch)
+ {
+ GNUNET_CADET_channel_destroy (ch);
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect client 1\n");
+ if (NULL != cadet_peer_1)
+ {
+ GNUNET_CADET_disconnect (cadet_peer_1);
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect client 2\n");
+ if (NULL != cadet_peer_2)
+ {
+ GNUNET_CADET_disconnect (cadet_peer_2);
+ }
+}
+
+
+/**
+ * Something went wrong and timed out. Kill everything and set error flag
+ */
+static void
+do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ABORT\n");
+ result = GNUNET_SYSERR;
+ abort_task = GNUNET_SCHEDULER_NO_TASK;
+ if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
+ {
+ GNUNET_SCHEDULER_cancel (shutdown_task);
+ shutdown_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ do_shutdown (cls, tc);
+}
+
+
+/**
+ * Function is called whenever a message is received.
+ *
+ * @param cls closure (set from GNUNET_CADET_connect)
+ * @param channel connection to the other end
+ * @param channel_ctx place to store local state associated with the channel
+ * @param message the actual message
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+static int
+data_callback (void *cls, struct GNUNET_CADET_Channel *channel,
+ void **channel_ctx,
+ const struct GNUNET_MessageHeader *message)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data callback! Shutting down.\n");
+ got_data = GNUNET_YES;
+ if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
+ GNUNET_SCHEDULER_cancel (shutdown_task);
+ shutdown_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_shutdown,
+ NULL);
+ GNUNET_CADET_receive_done (channel);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Method called whenever another peer has added us to a channel
+ * the other peer initiated.
+ *
+ * @param cls closure
+ * @param channel new handle to the channel
+ * @param initiator peer that started the channel
+ * @param port port number
+ * @param options channel options
+ * @return initial channel context for the channel
+ * (can be NULL -- that's not an error)
+ */
+static void *
+inbound_channel (void *cls, struct GNUNET_CADET_Channel *channel,
+ const struct GNUNET_PeerIdentity *initiator,
+ uint32_t port, enum GNUNET_CADET_ChannelOption options)
+{
+ long id = (long) cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "received incoming channel on peer %d, port %u\n",
+ id, port);
+ if (id != 2L)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "wrong peer\n");
+ result = GNUNET_SYSERR;
+ }
+ return NULL;
+}
+
+
+/**
+ * Function called whenever an channel is destroyed. Should clean up
+ * any associated state.
+ *
+ * @param cls closure (set from GNUNET_CADET_connect)
+ * @param channel connection to the other end (henceforth invalid)
+ * @param channel_ctx place where local state associated
+ * with the channel is stored
+ */
+static void
+channel_end (void *cls, const struct GNUNET_CADET_Channel *channel,
+ void *channel_ctx)
+{
+ long id = (long) cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "incoming channel closed at peer %ld\n",
+ id);
+ if (NULL != mth)
+ {
+ GNUNET_CADET_notify_transmit_ready_cancel (mth);
+ mth = NULL;
+ }
+ if (GNUNET_NO == got_data)
+ {
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (
+ GNUNET_TIME_UNIT_SECONDS,
+ 2),
+ &do_connect, NULL);
+ }
+}
+
+
+/**
+ * Handler array for traffic received on peer1
+ */
+static struct GNUNET_CADET_MessageHandler handlers1[] = {
+ {&data_callback, 1, 0},
+ {NULL, 0, 0}
+};
+
+
+/**
+ * Handler array for traffic received on peer2 (none expected)
+ */
+static struct GNUNET_CADET_MessageHandler handlers2[] = {
+ {&data_callback, 1, 0},
+ {NULL, 0, 0}
+};
+
+
+/**
+ * Data send callback: fillbuffer with test packet.
+ *
+ * @param cls Closure (unused).
+ * @param size Buffer size.
+ * @param buf Buffer to fill.
+ *
+ * @return size of test packet.
+ */
+static size_t
+do_send (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_MessageHeader *m = buf;
+
+ mth = NULL;
+ if (NULL == buf)
+ {
+ GNUNET_break (0);
+ result = GNUNET_SYSERR;
+ return 0;
+ }
+ m->size = htons (sizeof (struct GNUNET_MessageHeader));
+ m->type = htons (1);
+ GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
+ return sizeof (struct GNUNET_MessageHeader);
+}
+
+/**
+ * Connect to other client and send data
+ *
+ * @param cls Closue (unused).
+ * @param tc TaskContext.
+ */
+static void
+do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_PeerIdentity id;
+
+ if (NULL != tc && 0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+ return;
+
+ GNUNET_TESTING_peer_get_identity (me, &id);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CONNECT BY PORT\n");
+ ch = GNUNET_CADET_channel_create (cadet_peer_1, NULL, &id, 1,
+ GNUNET_CADET_OPTION_DEFAULT);
+ mth = GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ sizeof (struct
GNUNET_MessageHeader),
+ &do_send, NULL);
+}
+
+
+/**
+ * Initialize framework and start test
+ *
+ * @param cls Closure (unused).
+ * @param cfg Configuration handle.
+ * @param peer Testing peer handle.
+ */
+static void
+run (void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ struct GNUNET_TESTING_Peer *peer)
+{
+ static uint32_t ports[] = {1, 0};
+
+ me = peer;
+ abort_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS, 15), &do_abort,
+ NULL);
+ cadet_peer_1 = GNUNET_CADET_connect (cfg, /* configuration */
+ (void *) 1L, /* cls */
+ NULL, /* inbound new hndlr */
+ &channel_end, /* channel end hndlr */
+ handlers1, /* traffic handlers */
+ NULL); /* ports offered */
+
+ cadet_peer_2 = GNUNET_CADET_connect (cfg, /* configuration */
+ (void *) 2L, /* cls */
+ &inbound_channel, /* inbound new hndlr
*/
+ &channel_end, /* channel end hndlr */
+ handlers2, /* traffic handlers */
+ ports); /* ports offered */
+ if (NULL == cadet_peer_1 || NULL == cadet_peer_2)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Couldn't connect to cadet :(\n");
+ result = GNUNET_SYSERR;
+ return;
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "YAY! CONNECTED TO CADET :D\n");
+ }
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (
+ GNUNET_TIME_UNIT_SECONDS,
+ 2),
+ &do_connect, NULL);
+}
+
+
+/**
+ * Main
+ */
+int
+main (int argc, char *argv[])
+{
+ if (0 != GNUNET_TESTING_peer_run ("test-cadet-local",
+ "test_cadet.conf",
+ &run, NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "run failed\n");
+ return 2;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Final result: %d\n", result);
+ return (result == GNUNET_OK) ? 0 : 1;
+}
+
+/* end of test_cadet_local_1.c */
Copied: gnunet/src/cadet/test_cadet_single.c (from rev 33185,
gnunet/src/mesh/test_cadet_single.c)
===================================================================
--- gnunet/src/cadet/test_cadet_single.c (rev 0)
+++ gnunet/src/cadet/test_cadet_single.c 2014-05-07 12:07:16 UTC (rev
33186)
@@ -0,0 +1,329 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file cadet/test_cadet_single.c
+ * @brief test cadet single: test of cadet channels with just one client
+ * @author Bartlomiej Polot
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_dht_service.h"
+#include "gnunet_testing_lib.h"
+#include "gnunet_cadet_service.h"
+
+#define REPETITIONS 5
+#define DATA_SIZE 35000
+
+struct GNUNET_TESTING_Peer *me;
+
+static struct GNUNET_CADET_Handle *cadet;
+
+static struct GNUNET_CADET_Channel *ch1;
+
+static struct GNUNET_CADET_Channel *ch2;
+
+static int result;
+
+static GNUNET_SCHEDULER_TaskIdentifier abort_task;
+
+static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
+
+static unsigned int repetition;
+
+
+/* forward declaration */
+static size_t
+do_send (void *cls, size_t size, void *buf);
+
+
+/**
+ * Shutdown nicely
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutdown\n");
+ if (GNUNET_SCHEDULER_NO_TASK != abort_task)
+ {
+ GNUNET_SCHEDULER_cancel (abort_task);
+ }
+ if (NULL != ch1)
+ {
+ GNUNET_CADET_channel_destroy (ch1);
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect client 1\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect client 2\n");
+ if (NULL != cadet)
+ {
+ GNUNET_CADET_disconnect (cadet);
+ cadet = NULL;
+ }
+ else
+ {
+ GNUNET_break (0);
+ }
+}
+
+
+/**
+ * Something went wrong and timed out. Kill everything and set error flag
+ */
+static void
+do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ABORT\n");
+ result = GNUNET_SYSERR;
+ abort_task = GNUNET_SCHEDULER_NO_TASK;
+ if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
+ {
+ GNUNET_SCHEDULER_cancel (shutdown_task);
+ shutdown_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ do_shutdown (cls, tc);
+}
+
+
+static void
+finish (void)
+{
+ if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
+ GNUNET_SCHEDULER_cancel (shutdown_task);
+ shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+ &do_shutdown, NULL);
+}
+
+
+/**
+ * Function is called whenever a message is received.
+ *
+ * @param cls closure (set from GNUNET_CADET_connect)
+ * @param channel connection to the other end
+ * @param channel_ctx place to store local state associated with the channel
+ * @param message the actual message
+ *
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+static int
+data_callback (void *cls, struct GNUNET_CADET_Channel *channel,
+ void **channel_ctx,
+ const struct GNUNET_MessageHeader *message)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Data callback! Repetition %u/%u\n",
+ repetition, REPETITIONS);
+ repetition = repetition + 1;
+ if (repetition < REPETITIONS)
+ {
+ struct GNUNET_CADET_Channel *my_channel;
+ if (repetition % 2 == 0)
+ my_channel = ch1;
+ else
+ my_channel = ch2;
+ GNUNET_CADET_notify_transmit_ready (my_channel, GNUNET_NO,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ sizeof (struct GNUNET_MessageHeader)
+ + DATA_SIZE,
+ &do_send, NULL);
+ GNUNET_CADET_receive_done (channel);
+ return GNUNET_OK;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All data OK. Destroying channel.\n");
+ GNUNET_CADET_channel_destroy (ch1);
+ ch1 = NULL;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Method called whenever another peer has added us to a channel
+ * the other peer initiated.
+ *
+ * @param cls closure
+ * @param channel new handle to the channel
+ * @param initiator peer that started the channel
+ * @param port port number
+ * @param options channel option flags
+ * @return initial channel context for the channel
+ * (can be NULL -- that's not an error)
+ */
+static void *
+inbound_channel (void *cls, struct GNUNET_CADET_Channel *channel,
+ const struct GNUNET_PeerIdentity *initiator,
+ uint32_t port, enum GNUNET_CADET_ChannelOption options)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "received incoming channel on port %u\n",
+ port);
+ ch2 = channel;
+ return NULL;
+}
+
+
+/**
+ * Function called whenever an inbound channel is destroyed. Should clean up
+ * any associated state.
+ *
+ * @param cls closure (set from GNUNET_CADET_connect)
+ * @param channel connection to the other end (henceforth invalid)
+ * @param channel_ctx place where local state associated
+ * with the channel is stored
+ */
+static void
+channel_end (void *cls, const struct GNUNET_CADET_Channel *channel,
+ void *channel_ctx)
+{
+ long id = (long) cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "incoming channel closed at peer %ld\n",
+ id);
+ if (REPETITIONS == repetition && channel == ch2)
+ {
+ ch2 = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "everything fine! finishing!\n");
+ result = GNUNET_OK;
+ finish ();
+ }
+}
+
+
+/**
+ * Handler array for traffic received on peer1
+ */
+static struct GNUNET_CADET_MessageHandler handlers1[] = {
+ {&data_callback, 1, 0},
+ {NULL, 0, 0}
+};
+
+
+/**
+ * Data send callback: fillbuffer with test packet.
+ *
+ * @param cls Closure (unused).
+ * @param size Buffer size.
+ * @param buf Buffer to fill.
+ *
+ * @return size of test packet.
+ */
+static size_t
+do_send (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_MessageHeader *m = buf;
+
+ if (NULL == buf)
+ {
+ GNUNET_break (0);
+ result = GNUNET_SYSERR;
+ return 0;
+ }
+ m->size = htons (sizeof (struct GNUNET_MessageHeader));
+ m->type = htons (1);
+ memset (&m[1], 0, DATA_SIZE);
+ GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader) + DATA_SIZE);
+ return sizeof (struct GNUNET_MessageHeader) + DATA_SIZE;
+}
+
+/**
+ * Connect to other client and send data
+ *
+ * @param cls Closue (unused).
+ * @param tc TaskContext.
+ */
+static void
+do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_PeerIdentity id;
+ size_t size = sizeof (struct GNUNET_MessageHeader) + DATA_SIZE;
+
+ if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
+ return;
+
+ GNUNET_TESTING_peer_get_identity (me, &id);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CONNECT BY PORT\n");
+ ch1 = GNUNET_CADET_channel_create (cadet, NULL, &id, 1,
+ GNUNET_CADET_OPTION_DEFAULT);
+ GNUNET_CADET_notify_transmit_ready (ch1, GNUNET_NO,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ size, &do_send, NULL);
+}
+
+
+/**
+ * Initialize framework and start test
+ *
+ * @param cls Closure (unused).
+ * @param cfg Configuration handle.
+ * @param peer Testing peer handle.
+ */
+static void
+run (void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ struct GNUNET_TESTING_Peer *peer)
+{
+ static uint32_t ports[] = {1, 0};
+
+ me = peer;
+ abort_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS, 15), &do_abort,
+ NULL);
+ cadet = GNUNET_CADET_connect (cfg, /* configuration */
+ (void *) 1L, /* cls */
+ &inbound_channel, /* inbound new hndlr */
+ &channel_end, /* inbound end hndlr */
+ handlers1, /* traffic handlers */
+ ports); /* ports offered */
+
+ if (NULL == cadet)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Couldn't connect to cadet :(\n");
+ result = GNUNET_SYSERR;
+ return;
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "YAY! CONNECTED TO CADET :D\n");
+ }
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_connect, NULL);
+}
+
+
+/**
+ * Main
+ */
+int
+main (int argc, char *argv[])
+{
+ result = GNUNET_NO;
+ if (0 != GNUNET_TESTING_peer_run ("test-cadet-local",
+ "test_cadet.conf",
+ &run, NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "run failed\n");
+ return 2;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Final result: %d\n", result);
+ return (result == GNUNET_OK) ? 0 : 1;
+}
+
+/* end of test_cadet_single.c */
Copied: gnunet/src/cadet/valgrind-mesh.supp (from rev 33185,
gnunet/src/mesh/valgrind-mesh.supp)
===================================================================
--- gnunet/src/cadet/valgrind-mesh.supp (rev 0)
+++ gnunet/src/cadet/valgrind-mesh.supp 2014-05-07 12:07:16 UTC (rev 33186)
@@ -0,0 +1,116 @@
+{
+ logsetup_addr
+ Memcheck:Addr8
+ obj:/lib/libc-2.14.1.so
+ ...
+ fun:get_type
+ fun:GNUNET_log_setup
+ fun:GNUNET_SERVICE_run
+ fun:main
+}
+
+{
+ scanf_addr
+ Memcheck:Addr8
+ obj:/lib/libc-2.14.1.so
+ ...
+ fun:vsscanf
+ fun:sscanf
+ fun:GNUNET_CONFIGURATION_get_value_number
+ fun:GNUNET_SERVICE_get_server_addresses
+ fun:setup_service
+ fun:GNUNET_SERVICE_run
+ fun:main
+}
+
+{
+ mylog_addr
+ Memcheck:Addr8
+ obj:/lib/libc-2.14.1.so
+ ...
+ fun:service_task
+ fun:GNUNET_SCHEDULER_run
+ fun:GNUNET_SERVICE_run
+ fun:main
+}
+
+{
+ mylog_uninit
+ Memcheck:Value8
+ obj:/lib/libc-2.14.1.so
+ ...
+ fun:mylog
+ fun:GNUNET_log_from_nocheck
+ fun:service_task
+ ...
+ fun:GNUNET_SCHEDULER_run
+ fun:GNUNET_SERVICE_run
+ fun:main
+}
+
+{
+ mylog_from_cond
+ Memcheck:Cond
+ obj:/lib/libc-2.14.1.so
+ ...
+ fun:mylog
+ fun:GNUNET_log_from_nocheck
+ ...
+ fun:service_task
+ fun:GNUNET_SCHEDULER_run
+ fun:GNUNET_SERVICE_run
+ fun:main
+}
+
+{
+ mylog_cond
+ Memcheck:Cond
+ obj:/lib/libc-2.14.1.so
+ ...
+ fun:mylog
+ fun:GNUNET_log_nocheck
+ ...
+ fun:service_task
+ fun:GNUNET_SCHEDULER_run
+ fun:GNUNET_SERVICE_run
+ fun:main
+}
+
+{
+ inet_ntop_cond
+ Memcheck:Cond
+ obj:/lib/libc-2.14.1.so
+ ...
+ fun:inet_ntop
+ fun:GNUNET_a2s
+ ...
+ fun:service_task
+ fun:GNUNET_SCHEDULER_run
+ fun:GNUNET_SERVICE_run
+ fun:main
+}
+
+{
+ create_key_from_file
+ Memcheck:Addr8
+ obj:/lib/libc-2.14.1.so
+ ...
+ fun:GNUNET_CRYPTO_rsa_key_create_from_file
+ fun:run
+ fun:service_task
+ fun:GNUNET_SCHEDULER_run
+ fun:GNUNET_SERVICE_run
+ fun:main
+}
+
+{
+ main_notify_handler
+ Memcheck:Addr8
+ obj:/lib/libc-2.14.1.so
+ ...
+ fun:main_notify_handler
+ fun:receive_ready
+ fun:GNUNET_SCHEDULER_run
+ fun:GNUNET_SERVICE_run
+ fun:main
+}
\ No newline at end of file
Deleted: gnunet/src/mesh/Makefile.am
===================================================================
--- gnunet/src/mesh/Makefile.am 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/Makefile.am 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,194 +0,0 @@
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
-
-if MINGW
- WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
-endif
-
-if USE_COVERAGE
- AM_CFLAGS = --coverage -O0
- XLIB = -lgcov
-endif
-
-pkgcfgdir= $(pkgdatadir)/config.d/
-
-libexecdir= $(pkglibdir)/libexec/
-
-pkgcfg_DATA = \
- cadet.conf
-
-plugindir = $(libdir)/gnunet
-
-AM_CLFAGS = -g
-
-libexec_PROGRAMS = \
- gnunet-service-cadet $(EXP_LIBEXEC)
-
-bin_PROGRAMS = \
- gnunet-cadet
-
-lib_LTLIBRARIES = \
- libgnunetcadet.la $(EXP_LIB)
-
-libgnunetcadet_la_SOURCES = \
- cadet_api.c cadet_common.c
-libgnunetcadet_la_LIBADD = \
- $(top_builddir)/src/util/libgnunetutil.la \
- $(XLIB) \
- $(LTLIBINTL)
-libgnunetcadet_la_LDFLAGS = \
- $(GN_LIB_LDFLAGS) $(WINFLAGS) \
- -version-info 5:0:0
-
-gnunet_cadet_SOURCES = \
- gnunet-cadet.c
-gnunet_cadet_LDADD = \
- $(top_builddir)/src/cadet/libgnunetcadet.la \
- $(top_builddir)/src/util/libgnunetutil.la
-gnunet_cadet_DEPENDENCIES = \
- libgnunetcadet.la
-
-gnunet_service_cadet_SOURCES = \
- gnunet-service-cadet_tunnel.c gnunet-service-cadet_tunnel.h \
- gnunet-service-cadet_connection.c gnunet-service-cadet_connection.h \
- gnunet-service-cadet_channel.c gnunet-service-cadet_channel.h \
- gnunet-service-cadet_local.c gnunet-service-cadet_local.h \
- gnunet-service-cadet_peer.c gnunet-service-cadet_peer.h \
- gnunet-service-cadet_dht.c gnunet-service-cadet_dht.h \
- gnunet-service-cadet_hello.c gnunet-service-cadet_hello.h \
- cadet_path.c cadet_path.h \
- cadet_common.c \
- gnunet-service-cadet.c
-gnunet_service_cadet_CFLAGS = $(AM_CFLAGS)
-gnunet_service_cadet_LDADD = \
- $(top_builddir)/src/util/libgnunetutil.la \
- $(top_builddir)/src/transport/libgnunettransport.la \
- $(top_builddir)/src/core/libgnunetcore.la \
- $(top_builddir)/src/dht/libgnunetdht.la \
- $(top_builddir)/src/statistics/libgnunetstatistics.la \
- $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
- $(top_builddir)/src/hello/libgnunethello.la \
- $(top_builddir)/src/block/libgnunetblock.la
-gnunet_service_cadet_DEPENDENCIES = \
- $(top_builddir)/src/util/libgnunetutil.la \
- $(top_builddir)/src/transport/libgnunettransport.la \
- $(top_builddir)/src/core/libgnunetcore.la \
- $(top_builddir)/src/dht/libgnunetdht.la \
- $(top_builddir)/src/statistics/libgnunetstatistics.la \
- $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
- $(top_builddir)/src/hello/libgnunethello.la \
- $(top_builddir)/src/block/libgnunetblock.la
-if LINUX
- gnunet_service_cadet_LDFLAGS = -lrt
-endif
-
-
-if HAVE_TESTING
- noinst_LIBRARIES = libgnunetcadettest.a $(noinst_LIB_EXP)
- noinst_PROGRAMS = gnunet-cadet-profiler
-endif
-
-libgnunetcadettest_a_SOURCES = \
- cadet_test_lib.c cadet_test_lib.h
-libgnunetcadettest_a_LIBADD = \
- $(top_builddir)/src/util/libgnunetutil.la \
- $(top_builddir)/src/testbed/libgnunettestbed.la \
- $(top_builddir)/src/cadet/libgnunetcadet.la
-libgnunetcadettest_a_DEPENDENCIES = \
- libgnunetcadet.la
-
-if HAVE_TESTING
-check_PROGRAMS = \
- test_cadet_single \
- test_cadet_local \
- test_cadet_forward \
- test_cadet_signal \
- test_cadet_keepalive \
- test_cadet_speed \
- test_cadet_speed_ack \
- test_cadet_speed_backwards \
- test_cadet_speed_reliable \
- test_cadet_speed_reliable_backwards
-endif
-
-ld_cadet_test_lib = \
- $(top_builddir)/src/util/libgnunetutil.la \
- $(top_builddir)/src/testing/libgnunettesting.la \
- $(top_builddir)/src/cadet/libgnunetcadettest.a \
- $(top_builddir)/src/cadet/libgnunetcadet.la \
- $(top_builddir)/src/testbed/libgnunettestbed.la \
- $(top_builddir)/src/statistics/libgnunetstatistics.la
-
-dep_cadet_test_lib = \
- libgnunetcadet.la \
- libgnunetcadettest.a \
- $(top_builddir)/src/statistics/libgnunetstatistics.la
-
-
-gnunet_cadet_profiler_SOURCES = \
- gnunet-cadet-profiler.c
-gnunet_cadet_profiler_LDADD = $(ld_cadet_test_lib)
-gnunet_cadet_profiler_DEPENDENCIES = $(dep_cadet_test_lib)
-
-
-test_cadet_single_SOURCES = \
- test_cadet_single.c
-test_cadet_single_LDADD = $(ld_cadet_test_lib)
-test_cadet_single_DEPENDENCIES = $(dep_cadet_test_lib)
-
-test_cadet_local_SOURCES = \
- test_cadet_local.c
-test_cadet_local_LDADD = $(ld_cadet_test_lib)
-test_cadet_local_DEPENDENCIES = $(dep_cadet_test_lib)
-
-test_cadet_forward_SOURCES = \
- test_cadet.c
-test_cadet_forward_LDADD = $(ld_cadet_test_lib)
-test_cadet_forward_DEPENDENCIES = $(dep_cadet_test_lib)
-
-test_cadet_signal_SOURCES = \
- test_cadet.c
-test_cadet_signal_LDADD = $(ld_cadet_test_lib)
-test_cadet_signal_DEPENDENCIES = $(dep_cadet_test_lib)
-
-test_cadet_keepalive_SOURCES = \
- test_cadet.c
-test_cadet_keepalive_LDADD = $(ld_cadet_test_lib)
-test_cadet_keepalive_DEPENDENCIES = $(dep_cadet_test_lib)
-
-test_cadet_speed_SOURCES = \
- test_cadet.c
-test_cadet_speed_LDADD = $(ld_cadet_test_lib)
-test_cadet_speed_DEPENDENCIES = $(dep_cadet_test_lib)
-
-test_cadet_speed_ack_SOURCES = \
- test_cadet.c
-test_cadet_speed_ack_LDADD = $(ld_cadet_test_lib)
-test_cadet_speed_ack_DEPENDENCIES = $(dep_cadet_test_lib)
-
-test_cadet_speed_backwards_SOURCES = \
- test_cadet.c
-test_cadet_speed_backwards_LDADD = $(ld_cadet_test_lib)
-test_cadet_speed_backwards_DEPENDENCIES = $(dep_cadet_test_lib)
-
-test_cadet_speed_reliable_SOURCES = \
- test_cadet.c
-test_cadet_speed_reliable_LDADD = $(ld_cadet_test_lib)
-test_cadet_speed_reliable_DEPENDENCIES = $(dep_cadet_test_lib)
-
-test_cadet_speed_reliable_backwards_SOURCES = \
- test_cadet.c
-test_cadet_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib)
-test_cadet_speed_reliable_backwards_DEPENDENCIES = $(dep_cadet_test_lib)
-
-
-if ENABLE_TEST_RUN
-AM_TESTS_ENVIRONMENT=export
GNUNET_PREFIX=$${GNUNET_PREFIX:address@hidden@};export
PATH=$${GNUNET_PREFIX:address@hidden@}/bin:$$PATH;
-TESTS = \
- $(check_PROGRAMS)
-endif
-
-EXTRA_DIST = \
- cadet.h cadet_protocol.h \
- test_cadet.conf \
- test_cadet_drop.conf
-
Deleted: gnunet/src/mesh/beautify_log.sh
===================================================================
--- gnunet/src/mesh/beautify_log.sh 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/beautify_log.sh 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,18 +0,0 @@
-#!/bin/sh
-grep "STARTING SERVICE " log > __tmp_peers
-SED_EXPR=""
-while read -r line; do
- PEER=`echo $line | sed -e 's/.*\[\(....\)\].*/\1/'`
- PID=`echo $line | sed -e 's/.*mesh-\([0-9]*\).*/\1/'`
- echo "$PID => $PEER"
- SED_EXPR="${SED_EXPR}s/mesh-\([a-z2]*\)-$PID/MESH \1 $PEER/;"
- SED_EXPR="${SED_EXPR}s/mesh-$PID/MESH XXX $PEER/;"
-done < __tmp_peers
-rm __tmp_peers
-
-SED_EXPR="${SED_EXPR}s/mesh-api-/mesh-api-
/g"
-sed -e "$SED_EXPR" log > .log
-
-if [[ "`ps aux | grep "kwrite .lo[g]"`" = "" ]]; then
- kwrite .log --geometry 960x1140-960 &
-fi
Deleted: gnunet/src/mesh/cadet.h
===================================================================
--- gnunet/src/mesh/cadet.h 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/cadet.h 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,351 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2001 - 2011 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @author Bartlomiej Polot
- * @file cadet/cadet.h
- */
-
-#ifndef CADET_H_
-#define CADET_H_
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0 /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include <stdint.h>
-
-#define CADET_DEBUG GNUNET_YES
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_peer_lib.h"
-#include "gnunet_core_service.h"
-#include "gnunet_protocols.h"
-#include <gnunet_cadet_service.h>
-
-/******************************************************************************/
-/************************** CONSTANTS
******************************/
-/******************************************************************************/
-
-#define GNUNET_CADET_LOCAL_CHANNEL_ID_CLI 0x80000000
-#define GNUNET_CADET_LOCAL_CHANNEL_ID_SERV 0xB0000000
-
-#define HIGH_PID 0xFFFF0000
-#define LOW_PID 0x0000FFFF
-
-#define PID_OVERFLOW(pid, max) (pid > HIGH_PID && max < LOW_PID)
-
-/******************************************************************************/
-/************************** MESSAGES
******************************/
-/******************************************************************************/
-
-GNUNET_NETWORK_STRUCT_BEGIN
-
-/**
- * Message for a client to register to the service
- */
-struct GNUNET_CADET_ClientConnect
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT
- *
- * Size: sizeof(struct GNUNET_CADET_ClientConnect) +
- * sizeof(CADET_ApplicationType) * applications +
- * sizeof(uint16_t) * types
- */
- struct GNUNET_MessageHeader header;
- /* uint32_t list_ports[] */
-};
-
-
-/**
- * Type for channel numbering.
- * - Local channel numbers given by the service (incoming) are >= 0xB0000000
- * - Local channel numbers given by the client (created) are >= 0x80000000
- * - Global channel numbers are < 0x80000000
- */
-typedef uint32_t CADET_ChannelNumber;
-
-
-/**
- * Message for a client to create and destroy channels.
- */
-struct GNUNET_CADET_ChannelMessage
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_TUNNEL_[CREATE|DESTROY]
- *
- * Size: sizeof(struct GNUNET_CADET_ChannelMessage)
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * ID of a channel controlled by this client.
- */
- CADET_ChannelNumber channel_id GNUNET_PACKED;
-
- /**
- * Channel's peer
- */
- struct GNUNET_PeerIdentity peer;
-
- /**
- * Port of the channel.
- */
- uint32_t port GNUNET_PACKED;
-
- /**
- * Options.
- */
- uint32_t opt GNUNET_PACKED;
-};
-
-
-/**
- * Message for cadet data traffic.
- */
-struct GNUNET_CADET_LocalData
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * ID of the channel
- */
- uint32_t id GNUNET_PACKED;
-
- /**
- * Payload follows
- */
-};
-
-
-/**
- * Message to allow the client send more data to the service
- * (always service -> client).
- */
-struct GNUNET_CADET_LocalAck
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * ID of the channel allowed to send more data.
- */
- CADET_ChannelNumber channel_id GNUNET_PACKED;
-
-};
-
-
-/**
- * Message to inform the client about channels in the service.
- */
-struct GNUNET_CADET_LocalInfo
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO[_TUNNEL,_PEER]
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * ID of the channel allowed to send more data.
- */
- CADET_ChannelNumber channel_id GNUNET_PACKED;
-
- /**
- * ID of the owner of the channel (can be local peer).
- */
-// struct GNUNET_PeerIdentity owner;
-
- /**
- * ID of the destination of the channel (can be local peer).
- */
- struct GNUNET_PeerIdentity peer;
-};
-
-
-/**
- * Message to inform the client about one of the peers in the service.
- */
-struct GNUNET_CADET_LocalInfoPeer
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER[S]
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * Number of paths.
- */
- uint16_t paths GNUNET_PACKED;
-
- /**
- * Do we have a tunnel toward this peer?
- */
- int16_t tunnel GNUNET_PACKED;
-
- /**
- * ID of the destination of the tunnel (can be local peer).
- */
- struct GNUNET_PeerIdentity destination;
-
- /* If type == PEER (no 'S'): GNUNET_PeerIdentity paths[]
- * (each path ends in destination) */
-};
-
-/**
- * Message to inform the client about one of the tunnels in the service.
- */
-struct GNUNET_CADET_LocalInfoTunnel
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL[S]
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * Number of channels.
- */
- uint32_t channels GNUNET_PACKED;
-
- /**
- * ID of the destination of the tunnel (can be local peer).
- */
- struct GNUNET_PeerIdentity destination;
-
- /**
- * Number of connections.
- */
- uint32_t connections GNUNET_PACKED;
-
- /**
- * Encryption state.
- */
- uint16_t estate GNUNET_PACKED;
-
- /**
- * Connection state.
- */
- uint16_t cstate GNUNET_PACKED;
-
- /* If TUNNEL (no 'S'): GNUNET_PeerIdentity connection_ids[connections] */
- /* If TUNNEL (no 'S'): uint32_t channel_ids[channels] */
-};
-
-
-GNUNET_NETWORK_STRUCT_END
-
-
-
-/**
- * @brief Translate a fwd variable into a string representation, for logging.
- *
- * @param fwd Is FWD? (#GNUNET_YES or #GNUNET_NO)
- *
- * @return String representing FWD or BCK.
- */
-char *
-GM_f2s (int fwd);
-
-
-/**
- * Check if one pid is bigger than other, accounting for overflow.
- *
- * @param bigger Argument that should be bigger.
- * @param smaller Argument that should be smaller.
- *
- * @return True if bigger (arg1) has a higher value than smaller (arg 2).
- */
-int
-GM_is_pid_bigger (uint32_t bigger, uint32_t smaller);
-
-
-/**
- * Get the higher ACK value out of two values, taking in account overflow.
- *
- * @param a First ACK value.
- * @param b Second ACK value.
- *
- * @return Highest ACK value from the two.
- */
-uint32_t
-GM_max_pid (uint32_t a, uint32_t b);
-
-
-/**
- * Get the lower ACK value out of two values, taking in account overflow.
- *
- * @param a First ACK value.
- * @param b Second ACK value.
- *
- * @return Lowest ACK value from the two.
- */
-uint32_t
-GM_min_pid (uint32_t a, uint32_t b);
-
-
-/**
- * Convert a 256 bit CadetHash into a 512 HashCode to use in GNUNET_h2s,
- * multihashmap, and other HashCode-based functions.
- *
- * @param id A 256 bit hash to expand.
- *
- * @return A HashCode containing the original 256 bit hash right-padded with 0.
- */
-const struct GNUNET_HashCode *
-GM_h2hc (const struct GNUNET_CADET_Hash *id);
-
-/**
- * Get a string from a Cadet Hash (256 bits).
- * WARNING: Not reentrant (based on GNUNET_h2s).
- */
-const char *
-GM_h2s (const struct GNUNET_CADET_Hash *id);
-
-/**
- * Convert a message type into a string to help debug
- * Generated with:
- * FIND: "#define ([^ ]+)[ ]*([0-9]+)"
- * REPLACE: " case \2: return "\1"; break;"
- *
- * @param m Message type.
- *
- * @return Human readable string description.
- */
-const char *
-GM_m2s (uint16_t m);
-
-#if 0 /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-#endif
Deleted: gnunet/src/mesh/cadet_api.c
===================================================================
--- gnunet/src/mesh/cadet_api.c 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/cadet_api.c 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,2141 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2011 Christian Grothoff (and other contributing authors)
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file cadet/cadet_api.c
- * @brief cadet api: client implementation of new cadet service
- * @author Bartlomiej Polot
- */
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_cadet_service.h"
-#include "cadet.h"
-#include "cadet_protocol.h"
-
-#define LOG(kind,...) GNUNET_log_from (kind, "cadet-api",__VA_ARGS__)
-
-/******************************************************************************/
-/************************ DATA STRUCTURES
****************************/
-/******************************************************************************/
-
-/**
- * Transmission queue to the service
- */
-struct GNUNET_CADET_TransmitHandle
-{
-
- /**
- * Double Linked list
- */
- struct GNUNET_CADET_TransmitHandle *next;
-
- /**
- * Double Linked list
- */
- struct GNUNET_CADET_TransmitHandle *prev;
-
- /**
- * Channel this message is sent on / for (may be NULL for control
messages).
- */
- struct GNUNET_CADET_Channel *channel;
-
- /**
- * Callback to obtain the message to transmit, or NULL if we
- * got the message in 'data'. Notice that messages built
- * by 'notify' need to be encapsulated with information about
- * the 'target'.
- */
- GNUNET_CONNECTION_TransmitReadyNotify notify;
-
- /**
- * Closure for 'notify'
- */
- void *notify_cls;
-
- /**
- * How long is this message valid. Once the timeout has been
- * reached, the message must no longer be sent. If this
- * is a message with a 'notify' callback set, the 'notify'
- * function should be called with 'buf' NULL and size 0.
- */
- struct GNUNET_TIME_Absolute timeout;
-
- /**
- * Task triggering a timeout, can be NO_TASK if the timeout is FOREVER.
- */
- GNUNET_SCHEDULER_TaskIdentifier timeout_task;
-
- /**
- * Size of 'data' -- or the desired size of 'notify' if 'data' is NULL.
- */
- size_t size;
-};
-
-union CadetInfoCB {
-
- /**
- * Channel callback.
- */
- GNUNET_CADET_ChannelCB channel_cb;
-
- /**
- * Monitor callback
- */
- GNUNET_CADET_PeersCB peers_cb;
-
- /**
- * Monitor callback
- */
- GNUNET_CADET_PeerCB peer_cb;
-
- /**
- * Monitor callback
- */
- GNUNET_CADET_TunnelsCB tunnels_cb;
-
- /**
- * Tunnel callback.
- */
- GNUNET_CADET_TunnelCB tunnel_cb;
-};
-
-
-/**
- * Opaque handle to the service.
- */
-struct GNUNET_CADET_Handle
-{
-
- /**
- * Handle to the server connection, to send messages later
- */
- struct GNUNET_CLIENT_Connection *client;
-
- /**
- * Set of handlers used for processing incoming messages in the channels
- */
- const struct GNUNET_CADET_MessageHandler *message_handlers;
-
- /**
- * Number of handlers in the handlers array.
- */
- unsigned int n_handlers;
-
- /**
- * Ports open.
- */
- const uint32_t *ports;
-
- /**
- * Number of ports.
- */
- unsigned int n_ports;
-
- /**
- * Double linked list of the channels this client is connected to, head.
- */
- struct GNUNET_CADET_Channel *channels_head;
-
- /**
- * Double linked list of the channels this client is connected to, tail.
- */
- struct GNUNET_CADET_Channel *channels_tail;
-
- /**
- * Callback for inbound channel creation
- */
- GNUNET_CADET_InboundChannelNotificationHandler *new_channel;
-
- /**
- * Callback for inbound channel disconnection
- */
- GNUNET_CADET_ChannelEndHandler *cleaner;
-
- /**
- * Handle to cancel pending transmissions in case of disconnection
- */
- struct GNUNET_CLIENT_TransmitHandle *th;
-
- /**
- * Closure for all the handlers given by the client
- */
- void *cls;
-
- /**
- * Messages to send to the service, head.
- */
- struct GNUNET_CADET_TransmitHandle *th_head;
-
- /**
- * Messages to send to the service, tail.
- */
- struct GNUNET_CADET_TransmitHandle *th_tail;
-
- /**
- * chid of the next channel to create (to avoid reusing IDs often)
- */
- CADET_ChannelNumber next_chid;
-
- /**
- * Have we started the task to receive messages from the service
- * yet? We do this after we send the 'CADET_LOCAL_CONNECT' message.
- */
- int in_receive;
-
- /**
- * Configuration given by the client, in case of reconnection
- */
- const struct GNUNET_CONFIGURATION_Handle *cfg;
-
- /**
- * Time to the next reconnect in case one reconnect fails
- */
- struct GNUNET_TIME_Relative reconnect_time;
-
- /**
- * Task for trying to reconnect.
- */
- GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
-
- /**
- * Callback for an info task (only one active at a time).
- */
- union CadetInfoCB info_cb;
-
- /**
- * Info callback closure for @c info_cb.
- */
- void *info_cls;
-};
-
-
-/**
- * Description of a peer
- */
-struct GNUNET_CADET_Peer
-{
- /**
- * ID of the peer in short form
- */
- GNUNET_PEER_Id id;
-
- /**
- * Channel this peer belongs to
- */
- struct GNUNET_CADET_Channel *t;
-};
-
-
-/**
- * Opaque handle to a channel.
- */
-struct GNUNET_CADET_Channel
-{
-
- /**
- * DLL next
- */
- struct GNUNET_CADET_Channel *next;
-
- /**
- * DLL prev
- */
- struct GNUNET_CADET_Channel *prev;
-
- /**
- * Handle to the cadet this channel belongs to
- */
- struct GNUNET_CADET_Handle *cadet;
-
- /**
- * Local ID of the channel
- */
- CADET_ChannelNumber chid;
-
- /**
- * Port number.
- */
- uint32_t port;
-
- /**
- * Other end of the channel.
- */
- GNUNET_PEER_Id peer;
-
- /**
- * Any data the caller wants to put in here
- */
- void *ctx;
-
- /**
- * Size of packet queued in this channel
- */
- unsigned int packet_size;
-
- /**
- * Channel options: reliability, etc.
- */
- enum GNUNET_CADET_ChannelOption options;
-
- /**
- * Are we allowed to send to the service?
- */
- int allow_send;
-
-};
-
-
-/**
- * Implementation state for cadet's message queue.
- */
-struct CadetMQState
-{
- /**
- * The current transmit handle, or NULL
- * if no transmit is active.
- */
- struct GNUNET_CADET_TransmitHandle *th;
-
- /**
- * Channel to send the data over.
- */
- struct GNUNET_CADET_Channel *channel;
-};
-
-
-/******************************************************************************/
-/*********************** DECLARATIONS
*************************/
-/******************************************************************************/
-
-/**
- * Function called to send a message to the service.
- * "buf" will be NULL and "size" zero if the socket was closed for writing in
- * the meantime.
- *
- * @param cls closure, the cadet handle
- * @param size number of bytes available in buf
- * @param buf where the callee should write the connect message
- * @return number of bytes written to buf
- */
-static size_t
-send_callback (void *cls, size_t size, void *buf);
-
-
-/******************************************************************************/
-/*********************** AUXILIARY FUNCTIONS
*************************/
-/******************************************************************************/
-
-/**
- * Check if transmission is a payload packet.
- *
- * @param th Transmission handle.
- *
- * @return GNUNET_YES if it is a payload packet,
- * GNUNET_NO if it is a cadet management packet.
- */
-static int
-th_is_payload (struct GNUNET_CADET_TransmitHandle *th)
-{
- return (th->notify != NULL) ? GNUNET_YES : GNUNET_NO;
-}
-
-
-/**
- * Check whether there is any message ready in the queue and find the size.
- *
- * @param h Cadet handle.
- *
- * @return The size of the first ready message in the queue,
- * 0 if there is none.
- */
-static size_t
-message_ready_size (struct GNUNET_CADET_Handle *h)
-{
- struct GNUNET_CADET_TransmitHandle *th;
- struct GNUNET_CADET_Channel *ch;
-
- for (th = h->th_head; NULL != th; th = th->next)
- {
- ch = th->channel;
- if (GNUNET_NO == th_is_payload (th))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "# message internal\n");
- return th->size;
- }
- if (GNUNET_YES == ch->allow_send)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "# message payload ok\n");
- return th->size;
- }
- }
- return 0;
-}
-
-
-/**
- * Get the channel handler for the channel specified by id from the given
handle
- * @param h Cadet handle
- * @param chid ID of the wanted channel
- * @return handle to the required channel or NULL if not found
- */
-static struct GNUNET_CADET_Channel *
-retrieve_channel (struct GNUNET_CADET_Handle *h, CADET_ChannelNumber chid)
-{
- struct GNUNET_CADET_Channel *ch;
-
- ch = h->channels_head;
- while (ch != NULL)
- {
- if (ch->chid == chid)
- return ch;
- ch = ch->next;
- }
- return NULL;
-}
-
-
-/**
- * Create a new channel and insert it in the channel list of the cadet handle
- *
- * @param h Cadet handle
- * @param chid Desired chid of the channel, 0 to assign one automatically.
- *
- * @return Handle to the created channel.
- */
-static struct GNUNET_CADET_Channel *
-create_channel (struct GNUNET_CADET_Handle *h, CADET_ChannelNumber chid)
-{
- struct GNUNET_CADET_Channel *ch;
-
- ch = GNUNET_new (struct GNUNET_CADET_Channel);
- GNUNET_CONTAINER_DLL_insert (h->channels_head, h->channels_tail, ch);
- ch->cadet = h;
- if (0 == chid)
- {
- ch->chid = h->next_chid;
- while (NULL != retrieve_channel (h, h->next_chid))
- {
- h->next_chid++;
- h->next_chid &= ~GNUNET_CADET_LOCAL_CHANNEL_ID_SERV;
- h->next_chid |= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
- }
- }
- else
- {
- ch->chid = chid;
- }
- ch->allow_send = GNUNET_NO;
- return ch;
-}
-
-
-/**
- * Destroy the specified channel.
- * - Destroys all peers, calling the disconnect callback on each if needed
- * - Cancels all outgoing traffic for that channel, calling respective notifys
- * - Calls cleaner if channel was inbound
- * - Frees all memory used
- *
- * @param ch Pointer to the channel.
- * @param call_cleaner Whether to call the cleaner handler.
- *
- * @return Handle to the required channel or NULL if not found.
- */
-static void
-destroy_channel (struct GNUNET_CADET_Channel *ch, int call_cleaner)
-{
- struct GNUNET_CADET_Handle *h;
- struct GNUNET_CADET_TransmitHandle *th;
- struct GNUNET_CADET_TransmitHandle *next;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " destroy_channel %X\n", ch->chid);
-
- if (NULL == ch)
- {
- GNUNET_break (0);
- return;
- }
- h = ch->cadet;
-
- GNUNET_CONTAINER_DLL_remove (h->channels_head, h->channels_tail, ch);
-
- /* signal channel destruction */
- if ( (NULL != h->cleaner) && (0 != ch->peer) && (GNUNET_YES == call_cleaner)
)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " calling cleaner\n");
- h->cleaner (h->cls, ch, ch->ctx);
- }
-
- /* check that clients did not leave messages behind in the queue */
- for (th = h->th_head; NULL != th; th = next)
- {
- next = th->next;
- if (th->channel != ch)
- continue;
- /* Clients should have aborted their requests already.
- * Management traffic should be ok, as clients can't cancel that.
- * If the service crashed and we are reconnecting, it's ok.
- */
- GNUNET_break (GNUNET_NO == th_is_payload (th)
- || GNUNET_NO == h->in_receive);
- GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
-
- /* clean up request */
- if (GNUNET_SCHEDULER_NO_TASK != th->timeout_task)
- GNUNET_SCHEDULER_cancel (th->timeout_task);
- GNUNET_free (th);
- }
-
- /* if there are no more pending requests with cadet service, cancel active
request */
- /* Note: this should be unnecessary... */
- if ((0 == message_ready_size (h)) && (NULL != h->th))
- {
- GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
- h->th = NULL;
- }
-
- if (0 != ch->peer)
- GNUNET_PEER_change_rc (ch->peer, -1);
- GNUNET_free (ch);
- return;
-}
-
-
-/**
- * Notify client that the transmission has timed out
- *
- * @param cls closure
- * @param tc task context
- */
-static void
-timeout_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct GNUNET_CADET_TransmitHandle *th = cls;
- struct GNUNET_CADET_Handle *cadet;
-
- cadet = th->channel->cadet;
- GNUNET_CONTAINER_DLL_remove (cadet->th_head, cadet->th_tail, th);
- th->channel->packet_size = 0;
- if (GNUNET_YES == th_is_payload (th))
- th->notify (th->notify_cls, 0, NULL);
- GNUNET_free (th);
- if ((0 == message_ready_size (cadet)) && (NULL != cadet->th))
- {
- /* nothing ready to transmit, no point in asking for transmission */
- GNUNET_CLIENT_notify_transmit_ready_cancel (cadet->th);
- cadet->th = NULL;
- }
-}
-
-
-/**
- * Add a transmit handle to the transmission queue and set the
- * timeout if needed.
- *
- * @param h cadet handle with the queue head and tail
- * @param th handle to the packet to be transmitted
- */
-static void
-add_to_queue (struct GNUNET_CADET_Handle *h,
- struct GNUNET_CADET_TransmitHandle *th)
-{
- GNUNET_CONTAINER_DLL_insert_tail (h->th_head, h->th_tail, th);
- if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us == th->timeout.abs_value_us)
- return;
- th->timeout_task =
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
- (th->timeout), &timeout_transmission, th);
-}
-
-
-/**
- * Auxiliary function to send an already constructed packet to the service.
- * Takes care of creating a new queue element, copying the message and
- * calling the tmt_rdy function if necessary.
- *
- * @param h cadet handle
- * @param msg message to transmit
- * @param channel channel this send is related to (NULL if N/A)
- */
-static void
-send_packet (struct GNUNET_CADET_Handle *h,
- const struct GNUNET_MessageHeader *msg,
- struct GNUNET_CADET_Channel *channel);
-
-
-/**
- * Send an ack on the channel to confirm the processing of a message.
- *
- * @param ch Channel on which to send the ACK.
- */
-static void
-send_ack (struct GNUNET_CADET_Channel *ch)
-{
- struct GNUNET_CADET_LocalAck msg;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending ACK on channel %X\n", ch->chid);
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
- msg.header.size = htons (sizeof (msg));
- msg.channel_id = htonl (ch->chid);
-
- send_packet (ch->cadet, &msg.header, ch);
- return;
-}
-
-
-
-/**
- * Reconnect callback: tries to reconnect again after a failer previous
- * reconnecttion
- * @param cls closure (cadet handle)
- * @param tc task context
- */
-static void
-reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
-
-
-/**
- * Send a connect packet to the service with the applications and types
- * requested by the user.
- *
- * @param h The cadet handle.
- *
- */
-static void
-send_connect (struct GNUNET_CADET_Handle *h)
-{
- size_t size;
-
- size = sizeof (struct GNUNET_CADET_ClientConnect);
- size += h->n_ports * sizeof (uint32_t);
- {
- char buf[size] GNUNET_ALIGN;
- struct GNUNET_CADET_ClientConnect *msg;
- uint32_t *ports;
- uint16_t i;
-
- /* build connection packet */
- msg = (struct GNUNET_CADET_ClientConnect *) buf;
- msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT);
- msg->header.size = htons (size);
- ports = (uint32_t *) &msg[1];
- for (i = 0; i < h->n_ports; i++)
- {
- ports[i] = htonl (h->ports[i]);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " port %u\n",
- h->ports[i]);
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Sending %lu bytes long message with %u ports\n",
- ntohs (msg->header.size), h->n_ports);
- send_packet (h, &msg->header, NULL);
- }
-}
-
-
-/**
- * Reconnect to the service, retransmit all infomation to try to restore the
- * original state.
- *
- * @param h handle to the cadet
- *
- * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...)
- */
-static int
-do_reconnect (struct GNUNET_CADET_Handle *h)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, "******* RECONNECT *******\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, "******** on %p *******\n", h);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n");
-
- /* disconnect */
- if (NULL != h->th)
- {
- GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
- h->th = NULL;
- }
- if (NULL != h->client)
- {
- GNUNET_CLIENT_disconnect (h->client);
- }
-
- /* connect again */
- h->client = GNUNET_CLIENT_connect ("cadet", h->cfg);
- if (h->client == NULL)
- {
- h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time,
- &reconnect_cbk, h);
- h->reconnect_time =
- GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS,
- GNUNET_TIME_relative_multiply
- (h->reconnect_time, 2));
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Next retry in %s\n",
- GNUNET_STRINGS_relative_time_to_string (h->reconnect_time,
- GNUNET_NO));
- GNUNET_break (0);
- return GNUNET_NO;
- }
- else
- {
- h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
- }
- send_connect (h);
- return GNUNET_YES;
-}
-
-/**
- * Reconnect callback: tries to reconnect again after a failer previous
- * reconnecttion
- * @param cls closure (cadet handle)
- * @param tc task context
- */
-static void
-reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct GNUNET_CADET_Handle *h = cls;
-
- h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- return;
- do_reconnect (h);
-}
-
-
-/**
- * Reconnect to the service, retransmit all infomation to try to restore the
- * original state.
- *
- * @param h handle to the cadet
- *
- * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...)
- */
-static void
-reconnect (struct GNUNET_CADET_Handle *h)
-{
- struct GNUNET_CADET_Channel *ch;
- struct GNUNET_CADET_Channel *next;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Requested RECONNECT, destroying all channels\n");
- h->in_receive = GNUNET_NO;
- for (ch = h->channels_head; NULL != ch; ch = next)
- {
- next = ch->next;
- destroy_channel (ch, GNUNET_YES);
- }
- if (GNUNET_SCHEDULER_NO_TASK == h->reconnect_task)
- h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time,
- &reconnect_cbk, h);
-}
-
-
-/******************************************************************************/
-/*********************** RECEIVE HANDLERS
****************************/
-/******************************************************************************/
-
-/**
- * Process the new channel notification and add it to the channels in the
handle
- *
- * @param h The cadet handle
- * @param msg A message with the details of the new incoming channel
- */
-static void
-process_channel_created (struct GNUNET_CADET_Handle *h,
- const struct GNUNET_CADET_ChannelMessage *msg)
-{
- struct GNUNET_CADET_Channel *ch;
- CADET_ChannelNumber chid;
- uint32_t port;
-
- chid = ntohl (msg->channel_id);
- port = ntohl (msg->port);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating incoming channel %X:%u\n", chid,
port);
- if (chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV)
- {
- GNUNET_break (0);
- return;
- }
- if (NULL != h->new_channel)
- {
- void *ctx;
-
- ch = create_channel (h, chid);
- ch->allow_send = GNUNET_NO;
- ch->peer = GNUNET_PEER_intern (&msg->peer);
- ch->cadet = h;
- ch->chid = chid;
- ch->port = port;
- ch->options = ntohl (msg->opt);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " created channel %p\n", ch);
- ctx = h->new_channel (h->cls, ch, &msg->peer, ch->port, ch->options);
- if (NULL != ctx)
- ch->ctx = ctx;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "User notified\n");
- }
- else
- {
- struct GNUNET_CADET_ChannelMessage d_msg;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "No handler for incoming channels\n");
-
- d_msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
- d_msg.header.size = htons (sizeof (struct GNUNET_CADET_ChannelMessage));
- d_msg.channel_id = msg->channel_id;
- memset (&d_msg.peer, 0, sizeof (struct GNUNET_PeerIdentity));
- d_msg.port = 0;
- d_msg.opt = 0;
-
- send_packet (h, &d_msg.header, NULL);
- }
- return;
-}
-
-
-/**
- * Process the channel destroy notification and free associated resources
- *
- * @param h The cadet handle
- * @param msg A message with the details of the channel being destroyed
- */
-static void
-process_channel_destroy (struct GNUNET_CADET_Handle *h,
- const struct GNUNET_CADET_ChannelMessage *msg)
-{
- struct GNUNET_CADET_Channel *ch;
- CADET_ChannelNumber chid;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel Destroy received from service\n");
- chid = ntohl (msg->channel_id);
- ch = retrieve_channel (h, chid);
-
- if (NULL == ch)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "channel %X unknown\n", chid);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " destroying channel %X\n", ch->chid);
- destroy_channel (ch, GNUNET_YES);
-}
-
-
-/**
- * Process the incoming data packets, call appropriate handlers.
- *
- * @param h The cadet handle
- * @param message A message encapsulating the data
- */
-static void
-process_incoming_data (struct GNUNET_CADET_Handle *h,
- const struct GNUNET_MessageHeader *message)
-{
- const struct GNUNET_MessageHeader *payload;
- const struct GNUNET_CADET_MessageHandler *handler;
- struct GNUNET_CADET_LocalData *dmsg;
- struct GNUNET_CADET_Channel *ch;
- size_t size;
- unsigned int i;
- uint16_t type;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a data message!\n");
- dmsg = (struct GNUNET_CADET_LocalData *) message;
- ch = retrieve_channel (h, ntohl (dmsg->id));
- if (NULL == ch)
- {
- GNUNET_break (0);
- return;
- }
-
- payload = (struct GNUNET_MessageHeader *) &dmsg[1];
- LOG (GNUNET_ERROR_TYPE_DEBUG, " %s data on channel %s [%X]\n",
- GM_f2s (ch->chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV),
- GNUNET_i2s (GNUNET_PEER_resolve2 (ch->peer)), ntohl (dmsg->id));
-
- size = ntohs (message->size);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " %u bytes\n", size);
-
- if (NULL == ch)
- {
- /* Channel was ignored/destroyed, probably service didn't get it yet */
- LOG (GNUNET_ERROR_TYPE_DEBUG, " ignored!\n");
- return;
- }
- type = ntohs (payload->type);
- size = ntohs (payload->size);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " payload type %s\n", GM_m2s (type));
- for (i = 0; i < h->n_handlers; i++)
- {
- handler = &h->message_handlers[i];
- LOG (GNUNET_ERROR_TYPE_DEBUG, " checking handler for type %u\n",
- handler->type);
- if (handler->type == type)
- {
- if (GNUNET_OK !=
- handler->callback (h->cls, ch, &ch->ctx, payload))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "callback caused disconnection\n");
- GNUNET_CADET_channel_destroy (ch);
- return;
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "callback completed successfully\n");
- return;
- }
- }
- }
-}
-
-
-/**
- * Process a local ACK message, enabling the client to send
- * more data to the service.
- *
- * @param h Cadet handle.
- * @param message Message itself.
- */
-static void
-process_ack (struct GNUNET_CADET_Handle *h,
- const struct GNUNET_MessageHeader *message)
-{
- struct GNUNET_CADET_LocalAck *msg;
- struct GNUNET_CADET_Channel *ch;
- CADET_ChannelNumber chid;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Got an ACK!\n");
- msg = (struct GNUNET_CADET_LocalAck *) message;
- chid = ntohl (msg->channel_id);
- ch = retrieve_channel (h, chid);
- if (NULL == ch)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "ACK on unknown channel %X\n", chid);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X!\n", ch->chid);
- ch->allow_send = GNUNET_YES;
- if (NULL == h->th && 0 < ch->packet_size)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " tmt rdy was NULL, requesting!\n");
- h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, ch->packet_size,
- GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_YES, &send_callback,
h);
- }
-}
-
-
-/*
- * Process a local reply about info on all channels, pass info to the user.
- *
- * @param h Cadet handle.
- * @param message Message itself.
- */
-// static void
-// process_get_channels (struct GNUNET_CADET_Handle *h,
-// const struct GNUNET_MessageHeader *message)
-// {
-// struct GNUNET_CADET_LocalInfo *msg;
-//
-// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Get Channels messasge received\n");
-//
-// if (NULL == h->channels_cb)
-// {
-// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " ignored\n");
-// return;
-// }
-//
-// msg = (struct GNUNET_CADET_LocalInfo *) message;
-// if (ntohs (message->size) !=
-// (sizeof (struct GNUNET_CADET_LocalInfo) +
-// sizeof (struct GNUNET_PeerIdentity)))
-// {
-// GNUNET_break_op (0);
-// GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-// "Get channels message: size %hu - expected %u\n",
-// ntohs (message->size),
-// sizeof (struct GNUNET_CADET_LocalInfo));
-// return;
-// }
-// h->channels_cb (h->channels_cls,
-// ntohl (msg->channel_id),
-// &msg->owner,
-// &msg->destination);
-// }
-
-
-
-/*
- * Process a local monitor_channel reply, pass info to the user.
- *
- * @param h Cadet handle.
- * @param message Message itself.
- */
-// static void
-// process_show_channel (struct GNUNET_CADET_Handle *h,
-// const struct GNUNET_MessageHeader *message)
-// {
-// struct GNUNET_CADET_LocalInfo *msg;
-// size_t esize;
-//
-// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Show Channel messasge received\n");
-//
-// if (NULL == h->channel_cb)
-// {
-// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " ignored\n");
-// return;
-// }
-//
-// /* Verify message sanity */
-// msg = (struct GNUNET_CADET_LocalInfo *) message;
-// esize = sizeof (struct GNUNET_CADET_LocalInfo);
-// if (ntohs (message->size) != esize)
-// {
-// GNUNET_break_op (0);
-// GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-// "Show channel message: size %hu - expected %u\n",
-// ntohs (message->size),
-// esize);
-//
-// h->channel_cb (h->channel_cls, NULL, NULL);
-// h->channel_cb = NULL;
-// h->channel_cls = NULL;
-//
-// return;
-// }
-//
-// h->channel_cb (h->channel_cls,
-// &msg->destination,
-// &msg->owner);
-// }
-
-
-
-/**
- * Process a local reply about info on all tunnels, pass info to the user.
- *
- * @param h Cadet handle.
- * @param message Message itself.
- */
-static void
-process_get_peers (struct GNUNET_CADET_Handle *h,
- const struct GNUNET_MessageHeader *message)
-{
- struct GNUNET_CADET_LocalInfoPeer *msg;
- uint16_t size;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Get Peer messasge received\n");
-
- if (NULL == h->info_cb.peers_cb)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ignored\n");
- return;
- }
-
- size = ntohs (message->size);
- if (sizeof (struct GNUNET_CADET_LocalInfoPeer) > size)
- {
- h->info_cb.peers_cb (h->info_cls, NULL, -1, 0, 0);
- h->info_cb.peers_cb = NULL;
- h->info_cls = NULL;
- return;
- }
-
- msg = (struct GNUNET_CADET_LocalInfoPeer *) message;
- h->info_cb.peers_cb (h->info_cls, &msg->destination,
- (int) ntohs (msg->tunnel),
- (unsigned int ) ntohs (msg->paths),
- 0);
-}
-
-
-/**
- * Process a local peer info reply, pass info to the user.
- *
- * @param h Cadet handle.
- * @param message Message itself.
- */
-static void
-process_get_peer (struct GNUNET_CADET_Handle *h,
- const struct GNUNET_MessageHeader *message)
-{
- struct GNUNET_CADET_LocalInfoTunnel *msg;
- size_t esize;
- size_t msize;
- unsigned int ch_n;
- unsigned int c_n;
- struct GNUNET_CADET_Hash *conns;
- CADET_ChannelNumber *chns;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Get Tunnel messasge received\n");
- if (NULL == h->info_cb.tunnel_cb)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ignored\n");
- return;
- }
-
- /* Verify message sanity */
- msg = (struct GNUNET_CADET_LocalInfoTunnel *) message;
- msize = ntohs (message->size);
- esize = sizeof (struct GNUNET_CADET_LocalInfoTunnel);
- if (esize > msize)
- {
- GNUNET_break_op (0);
- h->info_cb.tunnel_cb (h->info_cls, NULL, 0, 0, NULL, NULL, 0, 0);
- goto clean_cls;
- }
- ch_n = ntohl (msg->channels);
- c_n = ntohl (msg->connections);
- esize += ch_n * sizeof (CADET_ChannelNumber);
- esize += c_n * sizeof (struct GNUNET_CADET_Hash);
- if (msize != esize)
- {
- GNUNET_break_op (0);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "m:%u, e: %u (%u ch, %u conn)\n",
- msize, esize, ch_n, c_n);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%u (%u ch, %u conn)\n",
- sizeof (struct GNUNET_CADET_LocalInfoTunnel),
- sizeof (CADET_ChannelNumber), sizeof (struct GNUNET_HashCode));
- h->info_cb.tunnel_cb (h->info_cls, NULL, 0, 0, NULL, NULL, 0, 0);
- goto clean_cls;
- }
-
- /* Call Callback with tunnel info. */
- conns = (struct GNUNET_CADET_Hash *) &msg[1];
- chns = (CADET_ChannelNumber *) &conns[c_n];
- h->info_cb.tunnel_cb (h->info_cls, &msg->destination,
- ch_n, c_n, chns, conns,
- ntohs (msg->estate), ntohs (msg->cstate));
-
- clean_cls:
- h->info_cb.tunnel_cb = NULL;
- h->info_cls = NULL;
-}
-
-
-/**
- * Process a local reply about info on all tunnels, pass info to the user.
- *
- * @param h Cadet handle.
- * @param message Message itself.
- */
-static void
-process_get_tunnels (struct GNUNET_CADET_Handle *h,
- const struct GNUNET_MessageHeader *message)
-{
- struct GNUNET_CADET_LocalInfoTunnel *msg;
- uint16_t size;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Get Tunnels messasge received\n");
-
- if (NULL == h->info_cb.tunnels_cb)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ignored\n");
- return;
- }
-
- size = ntohs (message->size);
- if (sizeof (struct GNUNET_CADET_LocalInfoTunnel) > size)
- {
- h->info_cb.tunnels_cb (h->info_cls, NULL, 0, 0, 0, 0);
- h->info_cb.tunnels_cb = NULL;
- h->info_cls = NULL;
- return;
- }
-
- msg = (struct GNUNET_CADET_LocalInfoTunnel *) message;
- h->info_cb.tunnels_cb (h->info_cls, &msg->destination,
- ntohl (msg->channels), ntohl (msg->connections),
- ntohs (msg->estate), ntohs (msg->cstate));
-
-}
-
-
-/**
- * Process a local tunnel info reply, pass info to the user.
- *
- * @param h Cadet handle.
- * @param message Message itself.
- */
-static void
-process_get_tunnel (struct GNUNET_CADET_Handle *h,
- const struct GNUNET_MessageHeader *message)
-{
- struct GNUNET_CADET_LocalInfoTunnel *msg;
- size_t esize;
- size_t msize;
- unsigned int ch_n;
- unsigned int c_n;
- struct GNUNET_CADET_Hash *conns;
- CADET_ChannelNumber *chns;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Get Tunnel messasge received\n");
- if (NULL == h->info_cb.tunnel_cb)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ignored\n");
- return;
- }
-
- /* Verify message sanity */
- msg = (struct GNUNET_CADET_LocalInfoTunnel *) message;
- msize = ntohs (message->size);
- esize = sizeof (struct GNUNET_CADET_LocalInfoTunnel);
- if (esize > msize)
- {
- GNUNET_break_op (0);
- h->info_cb.tunnel_cb (h->info_cls, NULL, 0, 0, NULL, NULL, 0, 0);
- goto clean_cls;
- }
- ch_n = ntohl (msg->channels);
- c_n = ntohl (msg->connections);
- esize += ch_n * sizeof (CADET_ChannelNumber);
- esize += c_n * sizeof (struct GNUNET_CADET_Hash);
- if (msize != esize)
- {
- GNUNET_break_op (0);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "m:%u, e: %u (%u ch, %u conn)\n",
- msize, esize, ch_n, c_n);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%u (%u ch, %u conn)\n",
- sizeof (struct GNUNET_CADET_LocalInfoTunnel),
- sizeof (CADET_ChannelNumber), sizeof (struct GNUNET_HashCode));
- h->info_cb.tunnel_cb (h->info_cls, NULL, 0, 0, NULL, NULL, 0, 0);
- goto clean_cls;
- }
-
- /* Call Callback with tunnel info. */
- conns = (struct GNUNET_CADET_Hash *) &msg[1];
- chns = (CADET_ChannelNumber *) &conns[c_n];
- h->info_cb.tunnel_cb (h->info_cls, &msg->destination,
- ch_n, c_n, chns, conns,
- ntohs (msg->estate), ntohs (msg->cstate));
-
-clean_cls:
- h->info_cb.tunnel_cb = NULL;
- h->info_cls = NULL;
-}
-
-
-/**
- * Function to process all messages received from the service
- *
- * @param cls closure
- * @param msg message received, NULL on timeout or fatal error
- */
-static void
-msg_received (void *cls, const struct GNUNET_MessageHeader *msg)
-{
- struct GNUNET_CADET_Handle *h = cls;
- uint16_t type;
-
- if (msg == NULL)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Cadet service disconnected, reconnecting\n", h);
- reconnect (h);
- return;
- }
- type = ntohs (msg->type);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Received a message: %s\n",
- GM_m2s (type));
- switch (type)
- {
- /* Notify of a new incoming channel */
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE:
- process_channel_created (h, (struct GNUNET_CADET_ChannelMessage *) msg);
- break;
- /* Notify of a channel disconnection */
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: /* TODO separate(gid
problem)*/
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK:
- process_channel_destroy (h, (struct GNUNET_CADET_ChannelMessage *) msg);
- break;
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA:
- process_incoming_data (h, msg);
- break;
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK:
- process_ack (h, msg);
- break;
-// case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNELS:
-// process_get_channels (h, msg);
-// break;
-// case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL:
-// process_show_channel (h, msg);
-// break;
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS:
- process_get_peers (h, msg);
- break;
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER:
- process_get_peer (h, msg);
- break;
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS:
- process_get_tunnels (h, msg);
- break;
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL:
- process_get_tunnel (h, msg);
- break;
-// case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL:
-// process_show_channel (h, msg);
-// break;
- default:
- /* We shouldn't get any other packages, log and ignore */
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "unsolicited message form service (type %s)\n",
- GM_m2s (ntohs (msg->type)));
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "message processed\n");
- if (GNUNET_YES == h->in_receive)
- {
- GNUNET_CLIENT_receive (h->client, &msg_received, h,
- GNUNET_TIME_UNIT_FOREVER_REL);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "in receive off, not calling CLIENT_receive\n");
- }
-}
-
-
-/******************************************************************************/
-/************************ SEND FUNCTIONS
****************************/
-/******************************************************************************/
-
-/**
- * Function called to send a message to the service.
- * "buf" will be NULL and "size" zero if the socket was closed for writing in
- * the meantime.
- *
- * @param cls closure, the cadet handle
- * @param size number of bytes available in buf
- * @param buf where the callee should write the connect message
- * @return number of bytes written to buf
- */
-static size_t
-send_callback (void *cls, size_t size, void *buf)
-{
- struct GNUNET_CADET_Handle *h = cls;
- struct GNUNET_CADET_TransmitHandle *th;
- struct GNUNET_CADET_TransmitHandle *next;
- struct GNUNET_CADET_Channel *ch;
- char *cbuf = buf;
- size_t tsize;
- size_t psize;
- size_t nsize;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, "# Send packet() Buffer %u\n", size);
- if ((0 == size) || (NULL == buf))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "# Received NULL send callback on %p\n", h);
- reconnect (h);
- h->th = NULL;
- return 0;
- }
- tsize = 0;
- next = h->th_head;
- nsize = message_ready_size (h);
- while ((NULL != (th = next)) && (0 < nsize) && (size >= nsize))
- {
- ch = th->channel;
- if (GNUNET_YES == th_is_payload (th))
- {
- struct GNUNET_CADET_LocalData *dmsg;
- struct GNUNET_MessageHeader *mh;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "# payload\n");
- if (GNUNET_NO == ch->allow_send)
- {
- /* This channel is not ready to transmit yet, try next message */
- next = th->next;
- continue;
- }
- ch->packet_size = 0;
- GNUNET_assert (size >= th->size);
- dmsg = (struct GNUNET_CADET_LocalData *) cbuf;
- mh = (struct GNUNET_MessageHeader *) &dmsg[1];
- psize = th->notify (th->notify_cls,
- size - sizeof (struct GNUNET_CADET_LocalData),
- mh);
- if (psize > 0)
- {
- psize += sizeof (struct GNUNET_CADET_LocalData);
- GNUNET_assert (size >= psize);
- dmsg->header.size = htons (psize);
- dmsg->id = htonl (ch->chid);
- dmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "# payload type %s\n",
- GM_m2s (ntohs (mh->type)));
- ch->allow_send = GNUNET_NO;
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "# callback returned size 0, "
- "application canceled transmission\n");
- }
- }
- else
- {
- struct GNUNET_MessageHeader *mh = (struct GNUNET_MessageHeader *) &th[1];
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "# cadet internal traffic, type %s\n",
- GM_m2s (ntohs (mh->type)));
- memcpy (cbuf, &th[1], th->size);
- psize = th->size;
- }
- if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (th->timeout_task);
- GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
- GNUNET_free (th);
- next = h->th_head;
- nsize = message_ready_size (h);
- cbuf += psize;
- size -= psize;
- tsize += psize;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "# total size: %u\n", tsize);
- h->th = NULL;
- size = message_ready_size (h);
- if (0 != size)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "# next size: %u\n", size);
- h->th =
- GNUNET_CLIENT_notify_transmit_ready (h->client, size,
- GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_YES, &send_callback, h);
- }
- else
- {
- if (NULL != h->th_head)
- LOG (GNUNET_ERROR_TYPE_DEBUG, "# can't transmit any more\n");
- else
- LOG (GNUNET_ERROR_TYPE_DEBUG, "# nothing left to transmit\n");
- }
- if (GNUNET_NO == h->in_receive)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "# start receiving from service\n");
- h->in_receive = GNUNET_YES;
- GNUNET_CLIENT_receive (h->client, &msg_received, h,
- GNUNET_TIME_UNIT_FOREVER_REL);
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "# Send packet() END\n");
- return tsize;
-}
-
-
-/**
- * Auxiliary function to send an already constructed packet to the service.
- * Takes care of creating a new queue element, copying the message and
- * calling the tmt_rdy function if necessary.
- *
- * @param h cadet handle
- * @param msg message to transmit
- * @param channel channel this send is related to (NULL if N/A)
- */
-static void
-send_packet (struct GNUNET_CADET_Handle *h,
- const struct GNUNET_MessageHeader *msg,
- struct GNUNET_CADET_Channel *channel)
-{
- struct GNUNET_CADET_TransmitHandle *th;
- size_t msize;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Sending message to service: %s\n",
- GM_m2s(ntohs(msg->type)));
- msize = ntohs (msg->size);
- th = GNUNET_malloc (sizeof (struct GNUNET_CADET_TransmitHandle) + msize);
- th->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
- th->size = msize;
- th->channel = channel;
- memcpy (&th[1], msg, msize);
- add_to_queue (h, th);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " queued\n");
- if (NULL != h->th)
- return;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " calling ntfy tmt rdy for %u bytes\n",
msize);
- h->th =
- GNUNET_CLIENT_notify_transmit_ready (h->client, msize,
- GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_YES, &send_callback, h);
-}
-
-
-/******************************************************************************/
-/********************** API CALL DEFINITIONS
*************************/
-/******************************************************************************/
-
-struct GNUNET_CADET_Handle *
-GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, void *cls,
- GNUNET_CADET_InboundChannelNotificationHandler
new_channel,
- GNUNET_CADET_ChannelEndHandler cleaner,
- const struct GNUNET_CADET_MessageHandler *handlers,
- const uint32_t *ports)
-{
- struct GNUNET_CADET_Handle *h;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_CADET_connect()\n");
- h = GNUNET_new (struct GNUNET_CADET_Handle);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " addr %p\n", h);
- h->cfg = cfg;
- h->new_channel = new_channel;
- h->cleaner = cleaner;
- h->client = GNUNET_CLIENT_connect ("cadet", cfg);
- if (h->client == NULL)
- {
- GNUNET_break (0);
- GNUNET_free (h);
- return NULL;
- }
- h->cls = cls;
- h->message_handlers = handlers;
- h->ports = ports;
- h->next_chid = GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
- h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
- h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
-
- if (NULL != ports && ports[0] != 0 && NULL == new_channel)
- {
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "no new channel handler given, ports parameter is useless!!\n");
- }
- if ((NULL == ports || ports[0] == 0) && NULL != new_channel)
- {
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "no ports given, new channel handler will never be called!!\n");
- }
- /* count handlers */
- for (h->n_handlers = 0;
- handlers && handlers[h->n_handlers].type;
- h->n_handlers++) ;
- for (h->n_ports = 0;
- ports && ports[h->n_ports];
- h->n_ports++) ;
- send_connect (h);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_CADET_connect() END\n");
- return h;
-}
-
-
-void
-GNUNET_CADET_disconnect (struct GNUNET_CADET_Handle *handle)
-{
- struct GNUNET_CADET_Channel *ch;
- struct GNUNET_CADET_Channel *aux;
- struct GNUNET_CADET_TransmitHandle *th;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "CADET DISCONNECT\n");
-
- ch = handle->channels_head;
- while (NULL != ch)
- {
- aux = ch->next;
- if (ch->chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV)
- {
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "channel %X not destroyed\n", ch->chid);
- }
- destroy_channel (ch, GNUNET_YES);
- ch = aux;
- }
- while ( (th = handle->th_head) != NULL)
- {
- struct GNUNET_MessageHeader *msg;
-
- /* Make sure it is an allowed packet (everything else should have been
- * already canceled).
- */
- GNUNET_break (GNUNET_NO == th_is_payload (th));
- msg = (struct GNUNET_MessageHeader *) &th[1];
- switch (ntohs(msg->type))
- {
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNELS:
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL:
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER:
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS:
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL:
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS:
- break;
- default:
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_ERROR, "unexpected msg %u\n",
- ntohs(msg->type));
- }
-
- GNUNET_CONTAINER_DLL_remove (handle->th_head, handle->th_tail, th);
- GNUNET_free (th);
- }
-
- if (NULL != handle->th)
- {
- GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
- handle->th = NULL;
- }
- if (NULL != handle->client)
- {
- GNUNET_CLIENT_disconnect (handle->client);
- handle->client = NULL;
- }
- if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task)
- {
- GNUNET_SCHEDULER_cancel(handle->reconnect_task);
- handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
- }
- GNUNET_free (handle);
-}
-
-
-/**
- * Create a new channel towards a remote peer.
- *
- * If the destination port is not open by any peer or the destination peer
- * does not accept the channel, #GNUNET_CADET_ChannelEndHandler will be called
- * for this channel.
- *
- * @param h cadet handle
- * @param channel_ctx client's channel context to associate with the channel
- * @param peer peer identity the channel should go to
- * @param port Port number.
- * @param options CadetOption flag field, with all desired option bits set to
1.
- *
- * @return handle to the channel
- */
-struct GNUNET_CADET_Channel *
-GNUNET_CADET_channel_create (struct GNUNET_CADET_Handle *h,
- void *channel_ctx,
- const struct GNUNET_PeerIdentity *peer,
- uint32_t port,
- enum GNUNET_CADET_ChannelOption options)
-{
- struct GNUNET_CADET_Channel *ch;
- struct GNUNET_CADET_ChannelMessage msg;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Creating new channel to %s:%u\n",
- GNUNET_i2s (peer), port);
- ch = create_channel (h, 0);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " at %p\n", ch);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " number %X\n", ch->chid);
- ch->ctx = channel_ctx;
- ch->peer = GNUNET_PEER_intern (peer);
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE);
- msg.header.size = htons (sizeof (struct GNUNET_CADET_ChannelMessage));
- msg.channel_id = htonl (ch->chid);
- msg.port = htonl (port);
- msg.peer = *peer;
- msg.opt = htonl (options);
- ch->allow_send = 0;
- send_packet (h, &msg.header, ch);
- return ch;
-}
-
-
-void
-GNUNET_CADET_channel_destroy (struct GNUNET_CADET_Channel *channel)
-{
- struct GNUNET_CADET_Handle *h;
- struct GNUNET_CADET_ChannelMessage msg;
- struct GNUNET_CADET_TransmitHandle *th;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying channel\n");
- h = channel->cadet;
-
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
- msg.header.size = htons (sizeof (struct GNUNET_CADET_ChannelMessage));
- msg.channel_id = htonl (channel->chid);
- memset (&msg.peer, 0, sizeof (struct GNUNET_PeerIdentity));
- msg.port = 0;
- msg.opt = 0;
- th = h->th_head;
- while (th != NULL)
- {
- struct GNUNET_CADET_TransmitHandle *aux;
- if (th->channel == channel)
- {
- aux = th->next;
- /* FIXME call the handler? */
- if (GNUNET_YES == th_is_payload (th))
- th->notify (th->notify_cls, 0, NULL);
- GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
- GNUNET_free (th);
- th = aux;
- }
- else
- th = th->next;
- }
-
- destroy_channel (channel, GNUNET_YES);
- send_packet (h, &msg.header, NULL);
-}
-
-
-/**
- * Get information about a channel.
- *
- * @param channel Channel handle.
- * @param option Query (GNUNET_CADET_OPTION_*).
- * @param ... dependant on option, currently not used
- *
- * @return Union with an answer to the query.
- */
-const union GNUNET_CADET_ChannelInfo *
-GNUNET_CADET_channel_get_info (struct GNUNET_CADET_Channel *channel,
- enum GNUNET_CADET_ChannelOption option, ...)
-{
- static int bool_flag;
- const union GNUNET_CADET_ChannelInfo *ret;
-
- switch (option)
- {
- case GNUNET_CADET_OPTION_NOBUFFER:
- case GNUNET_CADET_OPTION_RELIABLE:
- case GNUNET_CADET_OPTION_OOORDER:
- if (0 != (option & channel->options))
- bool_flag = GNUNET_YES;
- else
- bool_flag = GNUNET_NO;
- ret = (const union GNUNET_CADET_ChannelInfo *) &bool_flag;
- break;
- case GNUNET_CADET_OPTION_PEER:
- ret = (const union GNUNET_CADET_ChannelInfo *) GNUNET_PEER_resolve2
(channel->peer);
- break;
- default:
- GNUNET_break (0);
- return NULL;
- }
-
- return ret;
-}
-
-struct GNUNET_CADET_TransmitHandle *
-GNUNET_CADET_notify_transmit_ready (struct GNUNET_CADET_Channel *channel, int
cork,
- struct GNUNET_TIME_Relative maxdelay,
- size_t notify_size,
- GNUNET_CONNECTION_TransmitReadyNotify
notify,
- void *notify_cls)
-{
- struct GNUNET_CADET_TransmitHandle *th;
-
- GNUNET_assert (NULL != channel);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "CADET NOTIFY TRANSMIT READY\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X\n", channel->chid);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " allow_send %d\n", channel->allow_send);
- if (channel->chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV)
- LOG (GNUNET_ERROR_TYPE_DEBUG, " to origin\n");
- else
- LOG (GNUNET_ERROR_TYPE_DEBUG, " to destination\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, " payload size %u\n", notify_size);
- GNUNET_assert (NULL != notify);
- GNUNET_assert (0 == channel->packet_size); // Only one data packet allowed
- th = GNUNET_new (struct GNUNET_CADET_TransmitHandle);
- th->channel = channel;
- th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay);
- th->size = notify_size + sizeof (struct GNUNET_CADET_LocalData);
- channel->packet_size = th->size;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " total size %u\n", th->size);
- th->notify = notify;
- th->notify_cls = notify_cls;
- add_to_queue (channel->cadet, th);
- if (NULL != channel->cadet->th)
- return th;
- if (GNUNET_NO == channel->allow_send)
- return th;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " call client notify tmt rdy\n");
- channel->cadet->th =
- GNUNET_CLIENT_notify_transmit_ready (channel->cadet->client, th->size,
- GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_YES, &send_callback,
- channel->cadet);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "CADET NOTIFY TRANSMIT READY END\n");
- return th;
-}
-
-
-void
-GNUNET_CADET_notify_transmit_ready_cancel (struct GNUNET_CADET_TransmitHandle
*th)
-{
- struct GNUNET_CADET_Handle *cadet;
-
- th->channel->packet_size = 0;
- cadet = th->channel->cadet;
- if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (th->timeout_task);
- GNUNET_CONTAINER_DLL_remove (cadet->th_head, cadet->th_tail, th);
- GNUNET_free (th);
- if ((0 == message_ready_size (cadet)) && (NULL != cadet->th))
- {
- /* queue empty, no point in asking for transmission */
- GNUNET_CLIENT_notify_transmit_ready_cancel (cadet->th);
- cadet->th = NULL;
- }
-}
-
-
-void
-GNUNET_CADET_receive_done (struct GNUNET_CADET_Channel *channel)
-{
- send_ack (channel);
-}
-
-
-static void
-send_info_request (struct GNUNET_CADET_Handle *h, uint16_t type)
-{
- struct GNUNET_MessageHeader msg;
-
- msg.size = htons (sizeof (msg));
- msg.type = htons (type);
- send_packet (h, &msg, NULL);
-}
-
-
-/**
- * Request information about peers known to the running cadet service.
- * The callback will be called for every peer known to the service.
- * Only one info request (of any kind) can be active at once.
- *
- *
- * WARNING: unstable API, likely to change in the future!
- *
- * @param h Handle to the cadet peer.
- * @param callback Function to call with the requested data.
- * @param callback_cls Closure for @c callback.
- *
- * @return #GNUNET_OK / #GNUNET_SYSERR
- */
-int
-GNUNET_CADET_get_peers (struct GNUNET_CADET_Handle *h,
- GNUNET_CADET_PeersCB callback,
- void *callback_cls)
-{
- if (NULL != h->info_cb.peers_cb)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- send_info_request (h, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
- h->info_cb.peers_cb = callback;
- h->info_cls = callback_cls;
- return GNUNET_OK;
-}
-
-
-/**
- * Cancel a peer info request. The callback will not be called (anymore).
- *
- * WARNING: unstable API, likely to change in the future!
- *
- * @param h Cadet handle.
- *
- * @return Closure given to GNUNET_CADET_get_peers.
- */
-void *
-GNUNET_CADET_get_peers_cancel (struct GNUNET_CADET_Handle *h)
-{
- void *cls;
-
- cls = h->info_cls;
- h->info_cb.peers_cb = NULL;
- h->info_cls = NULL;
- return cls;
-}
-
-
-/**
- * Request information about a peer known to the running cadet peer.
- * The callback will be called for the tunnel once.
- * Only one info request (of any kind) can be active at once.
- *
- * WARNING: unstable API, likely to change in the future!
- *
- * @param h Handle to the cadet peer.
- * @param id Peer whose tunnel to examine.
- * @param callback Function to call with the requested data.
- * @param callback_cls Closure for @c callback.
- *
- * @return #GNUNET_OK / #GNUNET_SYSERR
- */
-int
-GNUNET_CADET_get_peer (struct GNUNET_CADET_Handle *h,
- const struct GNUNET_PeerIdentity *id,
- GNUNET_CADET_PeerCB callback,
- void *callback_cls)
-{
- struct GNUNET_CADET_LocalInfo msg;
-
- if (NULL != h->info_cb.peer_cb)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
-
- memset (&msg, 0, sizeof (msg));
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
- msg.peer = *id;
- send_packet (h, &msg.header, NULL);
- h->info_cb.peer_cb = callback;
- h->info_cls = callback_cls;
- return GNUNET_OK;
-}
-
-
-/**
- * Request information about tunnels of the running cadet peer.
- * The callback will be called for every tunnel of the service.
- * Only one info request (of any kind) can be active at once.
- *
- * WARNING: unstable API, likely to change in the future!
- *
- * @param h Handle to the cadet peer.
- * @param callback Function to call with the requested data.
- * @param callback_cls Closure for @c callback.
- *
- * @return #GNUNET_OK / #GNUNET_SYSERR
- */
-int
-GNUNET_CADET_get_tunnels (struct GNUNET_CADET_Handle *h,
- GNUNET_CADET_TunnelsCB callback,
- void *callback_cls)
-{
- if (NULL != h->info_cb.tunnels_cb)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- send_info_request (h, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
- h->info_cb.tunnels_cb = callback;
- h->info_cls = callback_cls;
- return GNUNET_OK;
-}
-
-
-/**
- * Cancel a monitor request. The monitor callback will not be called.
- *
- * @param h Cadet handle.
- *
- * @return Closure given to GNUNET_CADET_get_tunnels.
- */
-void *
-GNUNET_CADET_get_tunnels_cancel (struct GNUNET_CADET_Handle *h)
-{
- void *cls;
-
- h->info_cb.tunnels_cb = NULL;
- cls = h->info_cls;
- h->info_cls = NULL;
-
- return cls;
-}
-
-
-
-/**
- * Request information about a tunnel of the running cadet peer.
- * The callback will be called for the tunnel once.
- * Only one info request (of any kind) can be active at once.
- *
- * WARNING: unstable API, likely to change in the future!
- *
- * @param h Handle to the cadet peer.
- * @param id Peer whose tunnel to examine.
- * @param callback Function to call with the requested data.
- * @param callback_cls Closure for @c callback.
- *
- * @return #GNUNET_OK / #GNUNET_SYSERR
- */
-int
-GNUNET_CADET_get_tunnel (struct GNUNET_CADET_Handle *h,
- const struct GNUNET_PeerIdentity *id,
- GNUNET_CADET_TunnelCB callback,
- void *callback_cls)
-{
- struct GNUNET_CADET_LocalInfo msg;
-
- if (NULL != h->info_cb.tunnel_cb)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
-
- memset (&msg, 0, sizeof (msg));
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
- msg.peer = *id;
- send_packet (h, &msg.header, NULL);
- h->info_cb.tunnel_cb = callback;
- h->info_cls = callback_cls;
- return GNUNET_OK;
-}
-
-
-/**
- * Request information about a specific channel of the running cadet peer.
- *
- * WARNING: unstable API, likely to change in the future!
- * FIXME Add destination option.
- *
- * @param h Handle to the cadet peer.
- * @param initiator ID of the owner of the channel.
- * @param channel_number Channel number.
- * @param callback Function to call with the requested data.
- * @param callback_cls Closure for @c callback.
- *
- * @return #GNUNET_OK / #GNUNET_SYSERR
- */
-int
-GNUNET_CADET_show_channel (struct GNUNET_CADET_Handle *h,
- struct GNUNET_PeerIdentity *initiator,
- unsigned int channel_number,
- GNUNET_CADET_ChannelCB callback,
- void *callback_cls)
-{
- struct GNUNET_CADET_LocalInfo msg;
-
- if (NULL != h->info_cb.channel_cb)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
-
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL);
- msg.peer = *initiator;
- msg.channel_id = htonl (channel_number);
-// msg.reserved = 0;
- send_packet (h, &msg.header, NULL);
- h->info_cb.channel_cb = callback;
- h->info_cls = callback_cls;
- return GNUNET_OK;
-}
-
-
-/**
- * Function called to notify a client about the connection
- * begin ready to queue more data. "buf" will be
- * NULL and "size" zero if the connection was closed for
- * writing in the meantime.
- *
- * @param cls closure
- * @param size number of bytes available in buf
- * @param buf where the callee should write the message
- * @return number of bytes written to buf
- */
-static size_t
-cadet_mq_ntr (void *cls, size_t size,
- void *buf)
-{
- struct GNUNET_MQ_Handle *mq = cls;
- struct CadetMQState *state = GNUNET_MQ_impl_state (mq);
- const struct GNUNET_MessageHeader *msg = GNUNET_MQ_impl_current (mq);
- uint16_t msize;
-
- state->th = NULL;
- if (NULL == buf)
- {
- GNUNET_MQ_inject_error (mq, GNUNET_MQ_ERROR_WRITE);
- return 0;
- }
- msize = ntohs (msg->size);
- GNUNET_assert (msize <= size);
- memcpy (buf, msg, msize);
- GNUNET_MQ_impl_send_continue (mq);
- return msize;
-}
-
-
-/**
- * Signature of functions implementing the
- * sending functionality of a message queue.
- *
- * @param mq the message queue
- * @param msg the message to send
- * @param impl_state state of the implementation
- */
-static void
-cadet_mq_send_impl (struct GNUNET_MQ_Handle *mq,
- const struct GNUNET_MessageHeader *msg, void *impl_state)
-{
- struct CadetMQState *state = impl_state;
-
- GNUNET_assert (NULL == state->th);
- state->th =
- GNUNET_CADET_notify_transmit_ready (state->channel,
- /* FIXME: add option for corking */
- GNUNET_NO,
- GNUNET_TIME_UNIT_FOREVER_REL,
- ntohs (msg->size),
- cadet_mq_ntr, mq);
-
-}
-
-
-/**
- * Signature of functions implementing the
- * destruction of a message queue.
- * Implementations must not free 'mq', but should
- * take care of 'impl_state'.
- *
- * @param mq the message queue to destroy
- * @param impl_state state of the implementation
- */
-static void
-cadet_mq_destroy_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
-{
- struct CadetMQState *state = impl_state;
-
- if (NULL != state->th)
- GNUNET_CADET_notify_transmit_ready_cancel (state->th);
-
- GNUNET_free (state);
-}
-
-
-/**
- * Create a message queue for a cadet channel.
- * The message queue can only be used to transmit messages,
- * not to receive them.
- *
- * @param channel the channel to create the message qeue for
- * @return a message queue to messages over the channel
- */
-struct GNUNET_MQ_Handle *
-GNUNET_CADET_mq_create (struct GNUNET_CADET_Channel *channel)
-{
- struct GNUNET_MQ_Handle *mq;
- struct CadetMQState *state;
-
- state = GNUNET_new (struct CadetMQState);
- state->channel = channel;
-
- mq = GNUNET_MQ_queue_for_callbacks (cadet_mq_send_impl,
- cadet_mq_destroy_impl,
- NULL, /* FIXME: cancel impl. */
- state,
- NULL, /* no msg handlers */
- NULL, /* no err handlers */
- NULL); /* no handler cls */
- return mq;
-}
-
Deleted: gnunet/src/mesh/cadet_common.c
===================================================================
--- gnunet/src/mesh/cadet_common.c 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/cadet_common.c 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,348 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2012 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file cadet/cadet_common.c
- * @brief CADET helper functions
- * @author Bartlomiej Polot
- */
-
-#include "cadet.h"
-
-/**
- * @brief Translate a fwd variable into a string representation, for logging.
- *
- * @param fwd Is FWD? (#GNUNET_YES or #GNUNET_NO)
- *
- * @return String representing FWD or BCK.
- */
-char *
-GM_f2s (int fwd)
-{
- if (GNUNET_YES == fwd)
- {
- return "FWD";
- }
- else if (GNUNET_NO == fwd)
- {
- return "BCK";
- }
- else
- {
- /* Not an error, can happen with CONNECTION_BROKEN messages. */
- return "";
- }
-}
-
-int
-GM_is_pid_bigger (uint32_t bigger, uint32_t smaller)
-{
- return (GNUNET_YES == PID_OVERFLOW (smaller, bigger) ||
- (bigger > smaller && GNUNET_NO == PID_OVERFLOW (bigger, smaller)));
-}
-
-
-uint32_t
-GM_max_pid (uint32_t a, uint32_t b)
-{
- if (GM_is_pid_bigger(a, b))
- return a;
- return b;
-}
-
-
-uint32_t
-GM_min_pid (uint32_t a, uint32_t b)
-{
- if (GM_is_pid_bigger(a, b))
- return b;
- return a;
-}
-
-
-const struct GNUNET_HashCode *
-GM_h2hc (const struct GNUNET_CADET_Hash *id)
-{
- static struct GNUNET_HashCode hc;
- memcpy (&hc, id, sizeof (*id));
-
- return &hc;
-}
-
-
-const char *
-GM_h2s (const struct GNUNET_CADET_Hash *id)
-{
- static char s[53];
-
- memcpy (s, GNUNET_h2s_full (GM_h2hc (id)), 52);
- s[52] = '\0';
-
- return s;
-}
-
-
-#if !defined(GNUNET_CULL_LOGGING)
-const char *
-GM_m2s (uint16_t m)
-{
- static char buf[32];
- const char *t;
-
- switch (m)
- {
- /**
- * Request the creation of a path
- */
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
- t = "CONNECTION_CREATE";
- break;
-
- /**
- * Request the modification of an existing path
- */
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK:
- t = "CONNECTION_ACK";
- break;
-
- /**
- * Notify that a connection of a path is no longer valid
- */
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
- t = "CONNECTION_BROKEN";
- break;
-
- /**
- * At some point, the route will spontaneously change
- */
- case GNUNET_MESSAGE_TYPE_CADET_PATH_CHANGED:
- t = "PATH_CHANGED";
- break;
-
- /**
- * Transport payload data.
- */
- case GNUNET_MESSAGE_TYPE_CADET_DATA:
- t = "DATA";
- break;
-
- /**
- * Confirm receipt of payload data.
- */
- case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK:
- t = "DATA_ACK";
- break;
-
- /**
- * Key exchange encapsulation.
- */
- case GNUNET_MESSAGE_TYPE_CADET_KX:
- t = "KX";
- break;
-
- /**
- * New ephemeral key.
- */
- case GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL:
- t = "KX_EPHEMERAL";
- break;
-
- /**
- * Challenge to test peer's session key.
- */
- case GNUNET_MESSAGE_TYPE_CADET_KX_PING:
- t = "KX_PING";
- break;
-
- /**
- * Answer to session key challenge.
- */
- case GNUNET_MESSAGE_TYPE_CADET_KX_PONG:
- t = "KX_PONG";
- break;
-
- /**
- * Request the destuction of a path
- */
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
- t = "CONNECTION_DESTROY";
- break;
-
- /**
- * ACK for a data packet.
- */
- case GNUNET_MESSAGE_TYPE_CADET_ACK:
- t = "ACK";
- break;
-
- /**
- * POLL for ACK.
- */
- case GNUNET_MESSAGE_TYPE_CADET_POLL:
- t = "POLL";
- break;
-
- /**
- * Announce origin is still alive.
- */
- case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE:
- t = "KEEPALIVE";
- break;
-
- /**
- * Connect to the cadet service, specifying subscriptions
- */
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT:
- t = "LOCAL_CONNECT";
- break;
-
- /**
- * Ask the cadet service to create a new tunnel
- */
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE:
- t = "CHANNEL_CREATE";
- break;
-
- /**
- * Ask the cadet service to destroy a tunnel
- */
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
- t = "CHANNEL_DESTROY";
- break;
-
- /**
- * Confirm the creation of a channel.
- */
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK:
- t = "CHANNEL_ACK";
- break;
-
- /**
- * Confirm the creation of a channel.
- */
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK:
- t = "CHANNEL_NACK";
- break;
-
- /**
- * Encrypted payload.
- */
- case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
- t = "ENCRYPTED";
- break;
-
- /**
- * Local payload traffic
- */
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA:
- t = "LOCAL_DATA";
- break;
-
- /**
- * Local ACK for data.
- */
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK:
- t = "LOCAL_ACK";
- break;
-
- /**
- * Local monitoring of channels.
- */
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNELS:
- t = "LOCAL_INFO_CHANNELS";
- break;
-
- /**
- * Local monitoring of a channel.
- */
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL:
- t = "LOCAL_INFO_CHANNEL";
- break;
-
- /**
- * Local monitoring of service.
- */
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS:
- t = "LOCAL_INFO_TUNNELS";
- break;
-
- /**
- * Local monitoring of service.
- */
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL:
- t = "LOCAL_INFO_TUNNEL";
- break;
-
- /**
- * Local information about all connections of service.
- */
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CONNECTIONS:
- t = "LOCAL_INFO_CONNECTIONS";
- break;
-
- /**
- * Local information of service about a specific connection.
- */
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CONNECTION:
- t = "LOCAL_INFO_CONNECTION";
- break;
-
- /**
- * Local information about all peers known to the service.
- */
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS:
- t = "LOCAL_INFO_PEERS";
- break;
-
- /**
- * Local information of service about a specific peer.
- */
- case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER:
- t = "LOCAL_INFO_PEER";
- break;
-
- /**
- * Traffic (net-cat style) used by the Command Line Interface.
- */
- case GNUNET_MESSAGE_TYPE_CADET_CLI:
- t = "CLI";
- break;
-
- /**
- * 640kb should be enough for everybody
- */
- case 299:
- t = "RESERVE_END";
- break;
-
- default:
- sprintf(buf, "%u (UNKNOWN TYPE)", m);
- return buf;
- }
- sprintf(buf, "{%18s}", t);
- return buf;
-}
-#else
-const char *
-GM_m2s (uint16_t m)
-{
- return "";
-}
-#endif
Deleted: gnunet/src/mesh/cadet_path.c
===================================================================
--- gnunet/src/mesh/cadet_path.c 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/cadet_path.c 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,213 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2001 - 2013 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file cadet/cadet_path.c
- * @brief Path handling functions
- * @author Bartlomiej Polot
- */
-
-#include "cadet.h"
-#include "cadet_path.h"
-#include "gnunet-service-cadet_peer.h"
-
-/**
- * @brief Destroy a path after some time has past.
- *
- * If the path is returned from DHT again after a while, try again.
- *
- * @param cls Closure (path to destroy).
- * @param tc Task context.
- */
-static void
-path_destroy_delayed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct CadetPeerPath *path = cls;
- struct CadetPeer *peer;
-
- path->path_delete = GNUNET_SCHEDULER_NO_TASK;
- peer = GMP_get_short (path->peers[path->length - 1]);
- GMP_remove_path (peer, path);
-}
-
-
-/**
- * Create a new path
- *
- * @param length How many hops will the path have.
- *
- * @return A newly allocated path with a peer array of the specified length.
- */
-struct CadetPeerPath *
-path_new (unsigned int length)
-{
- struct CadetPeerPath *p;
-
- p = GNUNET_new (struct CadetPeerPath);
- if (length > 0)
- {
- p->length = length;
- p->peers = GNUNET_malloc (length * sizeof (GNUNET_PEER_Id));
- }
- return p;
-}
-
-
-/**
- * Invert the path
- *
- * @param path the path to invert
- */
-void
-path_invert (struct CadetPeerPath *path)
-{
- GNUNET_PEER_Id aux;
- unsigned int i;
-
- for (i = 0; i < path->length / 2; i++)
- {
- aux = path->peers[i];
- path->peers[i] = path->peers[path->length - i - 1];
- path->peers[path->length - i - 1] = aux;
- }
-}
-
-
-/**
- * Duplicate a path, incrementing short peer's rc.
- *
- * @param path The path to duplicate.
- */
-struct CadetPeerPath *
-path_duplicate (const struct CadetPeerPath *path)
-{
- struct CadetPeerPath *aux;
- unsigned int i;
-
- aux = path_new (path->length);
- memcpy (aux->peers, path->peers, path->length * sizeof (GNUNET_PEER_Id));
- for (i = 0; i < aux->length; i++)
- GNUNET_PEER_change_rc (aux->peers[i], 1);
- return aux;
-}
-
-
-/**
- * Get the length of a path.
- *
- * @param path The path to measure, with the local peer at any point of it.
- *
- * @return Number of hops to reach destination.
- * UINT_MAX in case the peer is not in the path.
- */
-unsigned int
-path_get_length (struct CadetPeerPath *path)
-{
- if (NULL == path)
- return UINT_MAX;
- return path->length;
-}
-
-
-
-/**
- * Mark path as invalid: keep it aroud for a while to avoid trying it in a
loop.
- *
- * DHT_get sometimes returns bad cached results, for instance, on a locally
- * cached result where the PUT followed a path that is no longer current.
- *
- * @param p Path to invalidate.
- */
-void
-path_invalidate (struct CadetPeerPath *p)
-{
- if (GNUNET_SCHEDULER_NO_TASK != p->path_delete)
- return;
-
- p->path_delete = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
- &path_destroy_delayed, p);
-}
-
-
-/**
- * Test if a path is valid (or at least not known to be invalid).
- *
- * @param path Path to test.
- *
- * @return #GNUNET_YES If the path is valid or unknown,
- * #GNUNET_NO If the path is known to be invalid.
- */
-int
-path_is_valid (const struct CadetPeerPath *path)
-{
- return (GNUNET_SCHEDULER_NO_TASK == path->path_delete);
-}
-
-
-/**
- * Destroy the path and free any allocated resources linked to it
- *
- * @param p the path to destroy
- *
- * @return GNUNET_OK on success
- */
-int
-path_destroy (struct CadetPeerPath *p)
-{
- if (NULL == p)
- return GNUNET_OK;
-
- GNUNET_PEER_decrement_rcs (p->peers, p->length);
- GNUNET_free_non_null (p->peers);
- if (GNUNET_SCHEDULER_NO_TASK != p->path_delete)
- GNUNET_SCHEDULER_cancel (p->path_delete);
- GNUNET_free (p);
- return GNUNET_OK;
-}
-
-char *
-path_2s (struct CadetPeerPath *p)
-{
- char *s;
- char *old;
- unsigned int i;
-
- old = GNUNET_strdup ("");
- for (i = 0; i < p->length; i++)
- {
- GNUNET_asprintf (&s, "%s %s",
- old, GNUNET_i2s (GNUNET_PEER_resolve2 (p->peers[i])));
- GNUNET_free_non_null (old);
- old = s;
- }
- return s;
-}
-
-void
-path_debug (struct CadetPeerPath *p)
-{
- unsigned int i;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "PATH:\n");
- for (i = 0; i < p->length; i++)
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %s\n",
- GNUNET_i2s (GNUNET_PEER_resolve2 (p->peers[i])));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "END\n");
-}
Deleted: gnunet/src/mesh/cadet_path.h
===================================================================
--- gnunet/src/mesh/cadet_path.h 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/cadet_path.h 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,185 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2001 - 2013 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file cadet/cadet_path.h
- * @brief Path handling functions
- * @author Bartlomiej Polot
- */
-
-#include "gnunet-service-cadet_connection.h"
-
-#ifndef CADET_PATH_H_
-#define CADET_PATH_H_
-
-#ifdef __cplusplus
-extern "C"
-{
- #if 0 /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-/******************************************************************************/
-/************************ DATA STRUCTURES
****************************/
-/******************************************************************************/
-
-/**
- * Information regarding a possible path to reach a single peer
- */
-struct CadetPeerPath
-{
-
- /**
- * Linked list
- */
- struct CadetPeerPath *next;
- struct CadetPeerPath *prev;
-
- /**
- * List of all the peers that form the path from origin to target.
- */
- GNUNET_PEER_Id *peers;
-
- /**
- * Number of peers (hops) in the path
- */
- unsigned int length;
-
- /**
- * User defined data store.
- */
- struct CadetConnection *c;
-
- /**
- * Path's score, how reliable is the path.
- */
-// int score;
-
- /**
- * Task to delete the path.
- * We tried it, it didn't work, don't try again in a while.
- */
- GNUNET_SCHEDULER_TaskIdentifier path_delete;
-
-};
-
-/******************************************************************************/
-/************************* FUNCTIONS
*****************************/
-/******************************************************************************/
-
-/**
- * Create a new path.
- *
- * @param length How many hops will the path have.
- *
- * @return A newly allocated path with a peer array of the specified length.
- */
-struct CadetPeerPath *
-path_new (unsigned int length);
-
-
-/**
- * Invert the path.
- *
- * @param path The path to invert.
- */
-void
-path_invert (struct CadetPeerPath *path);
-
-
-/**
- * Duplicate a path, incrementing short peer's rc.
- *
- * @param path The path to duplicate.
- */
-struct CadetPeerPath *
-path_duplicate (const struct CadetPeerPath *path);
-
-
-/**
- * Get the length of a path.
- *
- * @param path The path to measure, with the local peer at any point of it.
- *
- * @return Number of hops to reach destination.
- * UINT_MAX in case the peer is not in the path.
- */
-unsigned int
-path_get_length (struct CadetPeerPath *path);
-
-/**
- * Mark path as invalid: keep it aroud for a while to avoid trying it in a
loop.
- *
- * DHT_get sometimes returns bad cached results, for instance, on a locally
- * cached result where the PUT followed a path that is no longer current.
- *
- * @param p Path to invalidate.
- */
-void
-path_invalidate (struct CadetPeerPath *p);
-
-/**
- * Test if a path is valid (or at least not known to be invalid).
- *
- * @param path Path to test.
- *
- * @return #GNUNET_YES If the path is valid or unknown,
- * #GNUNET_NO If the path is known to be invalid.
- */
-int
-path_is_valid (const struct CadetPeerPath *path);
-
-/**
- * Destroy the path and free any allocated resources linked to it
- *
- * @param p the path to destroy
- *
- * @return GNUNET_OK on success
- */
-int
-path_destroy (struct CadetPeerPath *p);
-
-/**
- * Path -> allocated one line string. Caller must free.
- *
- * @param p Path.
- */
-char *
-path_2s (struct CadetPeerPath *p);
-
-/**
- * Print info about the path for debug.
- *
- * @param p Path to debug.
- */
-void
-path_debug (struct CadetPeerPath *p);
-
-#if 0 /* keep Emacsens' auto-indent happy */
-{
- #endif
- #ifdef __cplusplus
-}
-#endif
-
-
-/* ifndef CADET_PATH_H */
-#endif
Deleted: gnunet/src/mesh/cadet_protocol.h
===================================================================
--- gnunet/src/mesh/cadet_protocol.h 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/cadet_protocol.h 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,459 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2001 - 2011 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @author Bartlomiej Polot
- * @file cadet/cadet_protocol.h
- */
-
-#ifndef CADET_PROTOCOL_H_
-#define CADET_PROTOCOL_H_
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "cadet.h"
-
-#ifdef __cplusplus
-
-struct GNUNET_CADET_TunnelMessage;
-extern "C"
-{
-#if 0
- /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-/******************************************************************************/
-/******************** CADET NETWORK MESSAGES
**************************/
-/******************************************************************************/
-
-GNUNET_NETWORK_STRUCT_BEGIN
-
-/**
- * Message for cadet connection creation.
- */
-struct GNUNET_CADET_ConnectionCreate
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE
- *
- * Size: sizeof (struct GNUNET_CADET_ConnectionCreate) +
- * path_length * sizeof (struct GNUNET_PeerIdentity)
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * ID of the connection
- */
- struct GNUNET_CADET_Hash cid;
-
- /**
- * path_length structs defining the *whole* path from the origin [0] to the
- * final destination [path_length-1].
- */
- /* struct GNUNET_PeerIdentity peers[path_length]; */
-};
-
-/**
- * Message for ack'ing a connection
- */
-struct GNUNET_CADET_ConnectionACK
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * ID of the connection.
- */
- struct GNUNET_CADET_Hash cid;
-
-};
-
-
-/**
- * Message for encapsulation of a Key eXchange message in a connection.
- */
-struct GNUNET_CADET_KX
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_CADET_KX.
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * ID of the connection.
- */
- struct GNUNET_CADET_Hash cid;
-
- /* Specific KX message follows. */
-};
-
-
-/**
- * Message transmitted with the signed ephemeral key of a peer. The
- * session key is then derived from the two ephemeral keys (ECDHE).
- *
- * As far as possible, same as CORE's EphemeralKeyMessage.
- */
-struct GNUNET_CADET_KX_Ephemeral
-{
-
- /**
- * Message type is GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL.
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * Status of the sender (should be in "enum PeerStateMachine"), nbo.
- */
- int32_t sender_status GNUNET_PACKED;
-
- /**
- * An ECC signature of the 'origin' asserting the validity of
- * the given ephemeral key.
- */
- struct GNUNET_CRYPTO_EddsaSignature signature;
-
- /**
- * Information about what is being signed.
- */
- struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
-
- /**
- * At what time was this key created (beginning of validity).
- */
- struct GNUNET_TIME_AbsoluteNBO creation_time;
-
- /**
- * When does the given ephemeral key expire (end of validity).
- */
- struct GNUNET_TIME_AbsoluteNBO expiration_time;
-
- /**
- * Ephemeral public ECC key (always for NIST P-521) encoded in a format
suitable
- * for network transmission as created using 'gcry_sexp_sprint'.
- */
- struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
-
- /**
- * Public key of the signing peer (persistent version, not the ephemeral
public key).
- */
- struct GNUNET_PeerIdentity origin_identity;
-};
-
-
-/**
- * We're sending an (encrypted) PING to the other peer to check if he
- * can decrypt. The other peer should respond with a PONG with the
- * same content, except this time encrypted with the receiver's key.
- */
-struct GNUNET_CADET_KX_Ping
-{
- /**
- * Message type is GNUNET_MESSAGE_TYPE_CADET_KX_PING.
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * Seed for the IV
- */
- uint32_t iv GNUNET_PACKED;
-
- /**
- * Intended target of the PING, used primarily to check
- * that decryption actually worked.
- */
- struct GNUNET_PeerIdentity target;
-
- /**
- * Random number chosen to make reply harder.
- */
- uint32_t nonce GNUNET_PACKED;
-};
-
-
-/**
- * Response to a PING. Includes data from the original PING.
- */
-struct GNUNET_CADET_KX_Pong
-{
- /**
- * Message type is GNUNET_MESSAGE_TYPE_CADET_KX_PONG.
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * Seed for the IV
- */
- uint32_t iv GNUNET_PACKED;
-
- /**
- * Same nonce as in the reve.
- */
- uint32_t nonce GNUNET_PACKED;
-};
-
-
-/**
- * Tunnel(ed) message.
- */
-struct GNUNET_CADET_Encrypted
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * ID of the connection.
- */
- struct GNUNET_CADET_Hash cid;
-
- /**
- * ID of the packet (hop by hop).
- */
- uint32_t pid GNUNET_PACKED;
-
- /**
- * Number of hops to live.
- */
- uint32_t ttl GNUNET_PACKED;
-
- /**
- * Initialization Vector for payload encryption.
- */
- uint32_t iv GNUNET_PACKED;
-
- /**
- * MAC of the encrypted message, used to verify message integrity.
- * Everything after this value will be encrypted and authenticated.
- */
- struct GNUNET_CADET_Hash hmac;
-
- /**
- * Encrypted content follows.
- */
-};
-
-
-/**
- * Message to create a Channel.
- */
-struct GNUNET_CADET_ChannelCreate
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * ID of the channel
- */
- CADET_ChannelNumber chid GNUNET_PACKED;
-
- /**
- * Destination port.
- */
- uint32_t port GNUNET_PACKED;
-
- /**
- * Channel options.
- */
- uint32_t opt GNUNET_PACKED;
-};
-
-
-/**
- * Message to manage a Channel (ACK, NACK, Destroy).
- */
-struct GNUNET_CADET_ChannelManage
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_CADET_CHANNEL_{ACK|NACK|DESTROY}
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * ID of the channel
- */
- CADET_ChannelNumber chid GNUNET_PACKED;
-};
-
-
-/**
- * Message for cadet data traffic.
- */
-struct GNUNET_CADET_Data
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_CADET_UNICAST,
- * GNUNET_MESSAGE_TYPE_CADET_TO_ORIGIN
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * Unique ID of the payload message
- */
- uint32_t mid GNUNET_PACKED;
-
- /**
- * ID of the channel
- */
- CADET_ChannelNumber chid GNUNET_PACKED;
-
- /**
- * Payload follows
- */
-};
-
-
-/**
- * Message to acknowledge end-to-end data.
- */
-struct GNUNET_CADET_DataACK
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_CADET_DATA_ACK
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * ID of the channel
- */
- CADET_ChannelNumber chid GNUNET_PACKED;
-
- /**
- * Bitfield of already-received newer messages
- * pid + 1 @ LSB
- * pid + 64 @ MSB
- */
- uint64_t futures GNUNET_PACKED;
-
- /**
- * Last message ID received.
- */
- uint32_t mid GNUNET_PACKED;
-};
-
-
-/**
- * Message to acknowledge cadet encrypted traffic.
- */
-struct GNUNET_CADET_ACK
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_CADET_ACK
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * Maximum packet ID authorized.
- */
- uint32_t ack GNUNET_PACKED;
-
- /**
- * ID of the connection.
- */
- struct GNUNET_CADET_Hash cid;
-};
-
-
-/**
- * Message to query a peer about its Flow Control status regarding a tunnel.
- */
-struct GNUNET_CADET_Poll
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_CADET_POLL
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * Last packet sent.
- */
- uint32_t pid GNUNET_PACKED;
-
- /**
- * ID of the connection.
- */
- struct GNUNET_CADET_Hash cid;
-
-};
-
-
-/**
- * Message for notifying a disconnection in a path
- */
-struct GNUNET_CADET_ConnectionBroken
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * ID of the connection.
- */
- struct GNUNET_CADET_Hash cid;
-
- /**
- * ID of the endpoint
- */
- struct GNUNET_PeerIdentity peer1;
-
- /**
- * ID of the endpoint
- */
- struct GNUNET_PeerIdentity peer2;
-};
-
-
-/**
- * Message to destroy a connection.
- */
-struct GNUNET_CADET_ConnectionDestroy
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * ID of the connection.
- */
- struct GNUNET_CADET_Hash cid;
-};
-
-
-GNUNET_NETWORK_STRUCT_END
-
-#if 0 /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef CADET_PROTOCOL_H */
-#endif
-/* end of cadet_protocol.h */
Deleted: gnunet/src/mesh/cadet_test_lib.c
===================================================================
--- gnunet/src/mesh/cadet_test_lib.c 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/cadet_test_lib.c 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,295 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2012 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-/**
- * @file cadet/cadet_test_lib.c
- * @author Bartlomiej Polot
- * @brief library for writing CADET tests
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "cadet_test_lib.h"
-#include "gnunet_cadet_service.h"
-
-/**
- * Test context for a CADET Test.
- */
-struct GNUNET_CADET_TEST_Context
-{
- /**
- * Array of running peers.
- */
- struct GNUNET_TESTBED_Peer **peers;
-
- /**
- * Array of handles to the CADET for each peer.
- */
- struct GNUNET_CADET_Handle **cadetes;
-
- /**
- * Operation associated with the connection to the CADET.
- */
- struct GNUNET_TESTBED_Operation **ops;
-
- /**
- * Main function of the test to run once all CADETs are available.
- */
- GNUNET_CADET_TEST_AppMain app_main;
-
- /**
- * Closure for 'app_main'.
- */
- void *app_main_cls;
-
- /**
- * Number of peers running, size of the arrays above.
- */
- unsigned int num_peers;
-
- /**
- * Handler for incoming tunnels.
- */
- GNUNET_CADET_InboundChannelNotificationHandler *new_channel;
-
- /**
- * Cleaner for destroyed incoming tunnels.
- */
- GNUNET_CADET_ChannelEndHandler *cleaner;
-
- /**
- * Message handlers.
- */
- struct GNUNET_CADET_MessageHandler* handlers;
-
- /**
- * Application ports.
- */
- const uint32_t *ports;
-
-};
-
-
-/**
- * Context for a cadet adapter callback.
- */
-struct GNUNET_CADET_TEST_AdapterContext
-{
- /**
- * Peer number for the particular peer.
- */
- unsigned int peer;
-
- /**
- * General context.
- */
- struct GNUNET_CADET_TEST_Context *ctx;
-};
-
-
-/**
- * Adapter function called to establish a connection to
- * the CADET service.
- *
- * @param cls closure
- * @param cfg configuration of the peer to connect to; will be available until
- * GNUNET_TESTBED_operation_done() is called on the operation returned
- * from GNUNET_TESTBED_service_connect()
- * @return service handle to return in 'op_result', NULL on error
- */
-static void *
-cadet_connect_adapter (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
- struct GNUNET_CADET_TEST_Context *ctx = actx->ctx;
- struct GNUNET_CADET_Handle *h;
-
- h = GNUNET_CADET_connect (cfg,
- (void *) (long) actx->peer,
- ctx->new_channel,
- ctx->cleaner,
- ctx->handlers,
- ctx->ports);
- return h;
-}
-
-
-/**
- * Adapter function called to destroy a connection to
- * the CADET service.
- *
- * @param cls closure
- * @param op_result service handle returned from the connect adapter
- */
-static void
-cadet_disconnect_adapter (void *cls,
- void *op_result)
-{
- struct GNUNET_CADET_Handle *cadet = op_result;
- struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
-
- GNUNET_free (actx);
- GNUNET_CADET_disconnect (cadet);
-}
-
-
-/**
- * Callback to be called when a service connect operation is completed.
- *
- * @param cls The callback closure from functions generating an operation.
- * @param op The operation that has been finished.
- * @param ca_result The service handle returned from
- * GNUNET_TESTBED_ConnectAdapter() (cadet handle).
- * @param emsg Error message in case the operation has failed.
- * NULL if operation has executed successfully.
- */
-static void
-cadet_connect_cb (void *cls,
- struct GNUNET_TESTBED_Operation *op,
- void *ca_result,
- const char *emsg)
-{
- struct GNUNET_CADET_TEST_Context *ctx = cls;
- unsigned int i;
-
- if (NULL != emsg)
- {
- fprintf (stderr, "Failed to connect to CADET service: %s\n",
- emsg);
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- for (i = 0; i < ctx->num_peers; i++)
- if (op == ctx->ops[i])
- {
- ctx->cadetes[i] = ca_result;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "...cadet %u connected\n", i);
- }
- for (i = 0; i < ctx->num_peers; i++)
- if (NULL == ctx->cadetes[i])
- return; /* still some CADET connections missing */
- /* all CADET connections ready! */
- ctx->app_main (ctx->app_main_cls,
- ctx,
- ctx->num_peers,
- ctx->peers,
- ctx->cadetes);
-}
-
-
-void
-GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx)
-{
- unsigned int i;
-
- for (i = 0; i < ctx->num_peers; i++)
- {
- GNUNET_assert (NULL != ctx->ops[i]);
- GNUNET_TESTBED_operation_done (ctx->ops[i]);
- ctx->ops[i] = NULL;
- }
- GNUNET_free (ctx->ops);
- GNUNET_free (ctx->cadetes);
- GNUNET_free (ctx);
- GNUNET_SCHEDULER_shutdown ();
-}
-
-
-/**
- * Callback run when the testbed is ready (peers running and connected to
- * each other)
- *
- * @param cls Closure (context).
- * @param h the run handle
- * @param num_peers Number of peers that are running.
- * @param peers Handles to each one of the @c num_peers peers.
- * @param links_succeeded the number of overlay link connection attempts that
- * succeeded
- * @param links_failed the number of overlay link connection attempts that
- * failed
- */
-static void
-cadet_test_run (void *cls,
- struct GNUNET_TESTBED_RunHandle *h,
- unsigned int num_peers,
- struct GNUNET_TESTBED_Peer **peers,
- unsigned int links_succeeded,
- unsigned int links_failed)
-{
- struct GNUNET_CADET_TEST_Context *ctx = cls;
- unsigned int i;
-
- if (num_peers != ctx->num_peers)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers started %u/%u, ending\n",
- num_peers, ctx->num_peers);
- exit (1);
- }
- ctx->peers = peers;
- for (i = 0; i < num_peers; i++)
- {
- struct GNUNET_CADET_TEST_AdapterContext *newctx;
- newctx = GNUNET_new (struct GNUNET_CADET_TEST_AdapterContext);
- newctx->peer = i;
- newctx->ctx = ctx;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting to cadet %u\n", i);
- ctx->ops[i] = GNUNET_TESTBED_service_connect (ctx,
- peers[i],
- "cadet",
- &cadet_connect_cb,
- ctx,
- &cadet_connect_adapter,
- &cadet_disconnect_adapter,
- newctx);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "op handle %p\n", ctx->ops[i]);
- }
-}
-
-
-void
-GNUNET_CADET_TEST_run (const char *testname,
- const char *cfgname,
- unsigned int num_peers,
- GNUNET_CADET_TEST_AppMain tmain,
- void *tmain_cls,
- GNUNET_CADET_InboundChannelNotificationHandler
new_channel,
- GNUNET_CADET_ChannelEndHandler cleaner,
- struct GNUNET_CADET_MessageHandler* handlers,
- const uint32_t *ports)
-{
- struct GNUNET_CADET_TEST_Context *ctx;
-
- ctx = GNUNET_new (struct GNUNET_CADET_TEST_Context);
- ctx->num_peers = num_peers;
- ctx->ops = GNUNET_malloc (num_peers * sizeof (struct
GNUNET_TESTBED_Operation *));
- ctx->cadetes = GNUNET_malloc (num_peers * sizeof (struct GNUNET_CADET_Handle
*));
- ctx->app_main = tmain;
- ctx->app_main_cls = tmain_cls;
- ctx->new_channel = new_channel;
- ctx->cleaner = cleaner;
- ctx->handlers = handlers;
- ctx->ports = ports;
- GNUNET_TESTBED_test_run (testname,
- cfgname,
- num_peers,
- 0LL, NULL, NULL,
- &cadet_test_run, ctx);
-}
-
-/* end of cadet_test_lib.c */
Deleted: gnunet/src/mesh/cadet_test_lib.h
===================================================================
--- gnunet/src/mesh/cadet_test_lib.h 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/cadet_test_lib.h 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,106 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2012 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-/**
- * @file cadet/cadet_test_lib.h
- * @author Bartlomiej Polot
- * @brief library for writing CADET tests
- */
-#ifndef CADET_TEST_LIB_H
-#define CADET_TEST_LIB_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0 /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "gnunet_testbed_service.h"
-#include "gnunet_cadet_service.h"
-
-/**
- * Test context for a CADET Test.
- */
-struct GNUNET_CADET_TEST_Context;
-
-
-/**
- * Main function of a CADET test.
- *
- * @param cls Closure.
- * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
- * @param num_peers Number of peers that are running.
- * @param peers Array of peers.
- * @param cadetes Handle to each of the CADETs of the peers.
- */
-typedef void (*GNUNET_CADET_TEST_AppMain) (void *cls,
- struct GNUNET_CADET_TEST_Context
*ctx,
- unsigned int num_peers,
- struct GNUNET_TESTBED_Peer **peers,
- struct GNUNET_CADET_Handle
**cadetes);
-
-
-/**
- * Run a test using the given name, configuration file and number of
- * peers.
- * All cadet callbacks will receive the peer number as the closure.
- *
- * @param testname Name of the test (for logging).
- * @param cfgname Name of the configuration file.
- * @param num_peers Number of peers to start.
- * @param tmain Main function to run once the testbed is ready.
- * @param tmain_cls Closure for 'tmain'.
- * @param new_channel Handler for incoming tunnels.
- * @param cleaner Cleaner for destroyed incoming tunnels.
- * @param handlers Message handlers.
- * @param ports Ports the peers offer.
- */
-void
-GNUNET_CADET_TEST_run (const char *testname,
- const char *cfgname,
- unsigned int num_peers,
- GNUNET_CADET_TEST_AppMain tmain,
- void *tmain_cls,
- GNUNET_CADET_InboundChannelNotificationHandler
new_channel,
- GNUNET_CADET_ChannelEndHandler cleaner,
- struct GNUNET_CADET_MessageHandler* handlers,
- const uint32_t* ports);
-
-
-/**
- * Clean up the testbed.
- *
- * @param ctx handle for the testbed
- */
-void
-GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx);
-
-
-#if 0 /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-
-/* ifndef CADET_TEST_LIB_H */
-#endif
Deleted: gnunet/src/mesh/cadet_tunnel_tree.c
===================================================================
--- gnunet/src/mesh/cadet_tunnel_tree.c 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/cadet_tunnel_tree.c 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,1174 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2001 - 2011 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file cadet/cadet_tunnel_tree.c
- * @brief Tunnel tree handling functions
- * @author Bartlomiej Polot
- */
-
-#include "cadet.h"
-#include "cadet_tunnel_tree.h"
-
-#define CADET_TREE_DEBUG GNUNET_YES
-
-
-/**
- * Node of path tree for a tunnel
- */
-struct CadetTunnelTreeNode
-{
- /**
- * Peer this node describes
- */
- GNUNET_PEER_Id peer;
-
- /**
- * Parent node in the tree
- */
- struct CadetTunnelTreeNode *parent;
-
- /**
- * DLL of siblings
- */
- struct CadetTunnelTreeNode *next;
-
- /**
- * DLL of siblings
- */
- struct CadetTunnelTreeNode *prev;
-
- /**
- * DLL of children
- */
- struct CadetTunnelTreeNode *children_head;
-
- /**
- * DLL of children
- */
- struct CadetTunnelTreeNode *children_tail;
-
- /**
- * Status of the peer in the tunnel
- */
- enum CadetPeerState status;
-};
-
-
-/**
- * Tree to reach all peers in the tunnel
- */
-struct CadetTunnelTree
-{
- /**
- * Root node of peer tree
- */
- struct CadetTunnelTreeNode *root;
-
- /**
- * Node that represents our position in the tree (for non local tunnels)
- */
- struct CadetTunnelTreeNode *me;
-
- /**
- * DLL of disconneted nodes
- */
- struct CadetTunnelTreeNode *disconnected_head;
-
- /**
- * DLL of disconneted nodes
- */
- struct CadetTunnelTreeNode *disconnected_tail;
-
- /**
- * Cache of all peers and the first hop to them.
- * Indexed by PeerIdentity, contains a pointer to the PeerIdentity
- * of 1st hop.
- */
- struct GNUNET_CONTAINER_MultiHashMap *first_hops;
-
-};
-
-
-/**
- * Create a new path
- *
- * @param length How many hops will the path have.
- *
- * @return A newly allocated path with a peer array of the specified length.
- */
-struct CadetPeerPath *
-path_new (unsigned int length)
-{
- struct CadetPeerPath *p;
-
- p = GNUNET_new (struct CadetPeerPath);
- if (length > 0)
- {
- p->length = length;
- p->peers = GNUNET_malloc (length * sizeof (GNUNET_PEER_Id));
- }
- return p;
-}
-
-
-/**
- * Invert the path
- *
- * @param path the path to invert
- */
-void
-path_invert (struct CadetPeerPath *path)
-{
- GNUNET_PEER_Id aux;
- unsigned int i;
-
- for (i = 0; i < path->length / 2; i++)
- {
- aux = path->peers[i];
- path->peers[i] = path->peers[path->length - i - 1];
- path->peers[path->length - i - 1] = aux;
- }
-}
-
-
-/**
- * Duplicate a path, incrementing short peer's rc.
- *
- * @param path The path to duplicate.
- */
-struct CadetPeerPath *
-path_duplicate (struct CadetPeerPath *path)
-{
- struct CadetPeerPath *aux;
- unsigned int i;
-
- aux = path_new (path->length);
- memcpy (aux->peers, path->peers, path->length * sizeof (GNUNET_PEER_Id));
- for (i = 0; i < path->length; i++)
- GNUNET_PEER_change_rc (path->peers[i], 1);
- return aux;
-}
-
-
-/**
- * Recusively update the info about what is the first hop to reach the node
- *
- * @param tree Tree this nodes belongs to.
- * @param parent The node form which to start updating.
- * @param hop If known, ID of the first hop.
- * If not known, NULL to find out and pass on children.
- */
-static void
-tree_node_update_first_hops (struct CadetTunnelTree *tree,
- struct CadetTunnelTreeNode *parent,
- struct GNUNET_PeerIdentity *hop);
-
-
-/**
- * Get the length of a path.
- *
- * @param path The path to measure, with the local peer at any point of it.
- *
- * @return Number of hops to reach destination.
- * UINT_MAX in case the peer is not in the path.
- */
-unsigned int
-path_get_length (struct CadetPeerPath *path)
-{
- if (NULL == path)
- return UINT_MAX;
- return path->length;
-}
-
-
-/**
- * Destroy the path and free any allocated resources linked to it
- *
- * @param p the path to destroy
- *
- * @return GNUNET_OK on success
- */
-int
-path_destroy (struct CadetPeerPath *p)
-{
- if (NULL == p)
- return GNUNET_OK;
- GNUNET_PEER_decrement_rcs (p->peers, p->length);
- GNUNET_free_non_null (p->peers);
- GNUNET_free (p);
- return GNUNET_OK;
-}
-
-
-
-/**
- * Allocates and initializes a new node.
- * Sets ID and parent of the new node and inserts it in the DLL of the parent
- *
- * @param parent Node that will be the parent from the new node, NULL for root
- * @param peer Short Id of the new node
- *
- * @return Newly allocated node
- */
-static struct CadetTunnelTreeNode *
-tree_node_new (struct CadetTunnelTreeNode *parent, GNUNET_PEER_Id peer)
-{
- struct CadetTunnelTreeNode *node;
-
- node = GNUNET_new (struct CadetTunnelTreeNode);
- node->peer = peer;
- GNUNET_PEER_change_rc (peer, 1);
- node->parent = parent;
- if (NULL != parent)
- GNUNET_CONTAINER_DLL_insert (parent->children_head, parent->children_tail,
- node);
-
- return node;
-}
-
-
-/**
- * Recursively find the given peer.
- *
- * @param parent Node where to start looking.
- * @param peer_id Short ID of the peer to find.
- *
- * @return Pointer to the node of the peer. NULL if not found.
- */
-static struct CadetTunnelTreeNode *
-tree_node_find_peer (struct CadetTunnelTreeNode *parent, GNUNET_PEER_Id
peer_id)
-{
- struct CadetTunnelTreeNode *n;
- struct CadetTunnelTreeNode *r;
-
- if (parent->peer == peer_id)
- return parent;
- for (n = parent->children_head; NULL != n; n = n->next)
- {
- r = tree_node_find_peer (n, peer_id);
- if (NULL != r)
- return r;
- }
- return NULL;
-}
-
-
-/**
- * Recusively update the info about what is the first hop to reach the node
- *
- * @param tree Tree this nodes belongs to.
- * @param parent ID from node form which to start updating.
- * @param hop If known, ID of the first hop.
- * If not known, NULL to find out and pass on children.
- */
-static void
-tree_node_update_first_hops (struct CadetTunnelTree *tree,
- struct CadetTunnelTreeNode *parent,
- struct GNUNET_PeerIdentity *hop)
-{
- struct GNUNET_PeerIdentity pi;
- struct GNUNET_PeerIdentity *copy;
- struct GNUNET_PeerIdentity id;
- struct CadetTunnelTreeNode *n;
-
-#if CADET_TREE_DEBUG
- GNUNET_PEER_resolve (parent->peer, &id);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Finding first hop for %s.\n",
- GNUNET_i2s (&id));
-#endif
- if (NULL == hop)
- {
- struct CadetTunnelTreeNode *aux;
- struct CadetTunnelTreeNode *old;
-
- aux = old = parent;
- while (aux != tree->me)
- {
-#if CADET_TREE_DEBUG
- GNUNET_PEER_resolve (aux->peer, &id);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: ... checking %s.\n",
- GNUNET_i2s (&id));
-#endif
- old = aux;
- aux = aux->parent;
- GNUNET_assert (NULL != aux);
- }
-#if CADET_TREE_DEBUG
- GNUNET_PEER_resolve (old->peer, &id);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: It's %s!\n",
- GNUNET_i2s (&id));
-#endif
- hop = π
- GNUNET_PEER_resolve (old->peer, hop);
- }
- GNUNET_PEER_resolve (parent->peer, &id);
- copy = GNUNET_CONTAINER_multihashmap_get (tree->first_hops, &id.hashPubKey);
- if (NULL == copy)
- copy = GNUNET_new (struct GNUNET_PeerIdentity);
- *copy = *hop;
-
- (void) GNUNET_CONTAINER_multihashmap_put (tree->first_hops, &id.hashPubKey,
- copy,
-
GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
-
- for (n = parent->children_head; NULL != n; n = n->next)
- {
- tree_node_update_first_hops (tree, n, hop);
- }
-}
-
-
-static void
-tree_node_debug (struct CadetTunnelTreeNode *n, uint16_t level)
-{
- struct CadetTunnelTreeNode *c;
- struct GNUNET_PeerIdentity id;;
- uint16_t i;
-
- for (i = 0; i < level; i++)
- FPRINTF (stderr, "%s", " ");
- if (n->status == CADET_PEER_READY)
- FPRINTF (stderr, "%s", "#");
- if (n->status == CADET_PEER_SEARCHING)
- FPRINTF (stderr, "%s", "+");
- if (n->status == CADET_PEER_RELAY)
- FPRINTF (stderr, "%s", "-");
- if (n->status == CADET_PEER_RECONNECTING)
- FPRINTF (stderr, "%s", "*");
-
- GNUNET_PEER_resolve (n->peer, &id);
- FPRINTF (stderr, "%s, [%u, %p] ", GNUNET_i2s (&id), n->peer, n);
- if (NULL != n->parent)
- {
- GNUNET_PEER_resolve (n->parent->peer, &id);
- FPRINTF (stderr, "(-> %s [%u])\n", GNUNET_i2s (&id), n->parent->peer);
- }
- else
- FPRINTF (stderr, "%s", "(root)\n");
- for (c = n->children_head; NULL != c; c = c->next)
- tree_node_debug (c, level + 1);
-}
-
-
-/**
- * Destroys and frees the node and all children
- *
- * @param parent Parent node to be destroyed
- */
-static void
-tree_node_destroy (struct CadetTunnelTreeNode *parent)
-{
- struct CadetTunnelTreeNode *n;
- struct CadetTunnelTreeNode *next;
-
- if (NULL == parent)
- return;
-#if CADET_TREE_DEBUG
- struct GNUNET_PeerIdentity id;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Destroying node %u\n",
- parent->peer);
- GNUNET_PEER_resolve (parent->peer, &id);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: (%s)\n", GNUNET_i2s (&id));
-#endif
- n = parent->children_head;
- while (NULL != n)
- {
- next = n->next;
- tree_node_destroy (n);
- n = next;
- }
- GNUNET_PEER_change_rc (parent->peer, -1);
- if (NULL != parent->parent)
- GNUNET_CONTAINER_DLL_remove (parent->parent->children_head,
- parent->parent->children_tail, parent);
- GNUNET_free (parent);
-}
-
-
-
-/**
- * Create a new tree.
- *
- * @param peer A short peer id of the root of the tree.
- *
- * @return A newly allocated and initialized tunnel tree.
- */
-struct CadetTunnelTree *
-tree_new (GNUNET_PEER_Id peer)
-{
- struct CadetTunnelTree *tree;
-
- tree = GNUNET_new (struct CadetTunnelTree);
- tree->first_hops = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO);
- tree->root = tree_node_new (NULL, peer);
- tree->root->status = CADET_PEER_ROOT;
-
- if (1 == peer)
- {
- tree->me = tree->root;
- }
-
- return tree;
-}
-
-
-/**
- * Set the status of a node.
- *
- * @param tree Tree.
- * @param peer A short peer id of the node.
- * @param status New status to set.
- */
-void
-tree_set_status (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer,
- enum CadetPeerState status)
-{
- struct CadetTunnelTreeNode *n;
-
- n = tree_find_peer (tree, peer);
- if (NULL == n)
- return;
- n->status = status;
-}
-
-
-/**
- * Get the status of a node.
- *
- * @param tree Tree whose node's status we want to now.
- * @param peer A short peer id of the node.
- *
- * @return Status of the peer.
- */
-enum CadetPeerState
-tree_get_status (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer)
-{
- struct CadetTunnelTreeNode *n;
-
- n = tree_find_peer (tree, peer);
- if (NULL == n)
- return CADET_PEER_INVALID;
- return n->status;
-}
-
-
-/**
- * Get the id of the predecessor of the local node.
- *
- * @param tree Tree whose local id we want to now.
- *
- * @return Short peer id of local peer.
- */
-GNUNET_PEER_Id
-tree_get_predecessor (struct CadetTunnelTree *tree)
-{
- if (NULL != tree->me && NULL != tree->me->parent)
- return tree->me->parent->peer;
- else
- return (GNUNET_PEER_Id) 0;
-}
-
-
-/**
- * Find the first peer whom to send a packet to go down this path
- *
- * @param t The tunnel tree to use
- * @param peer The peerinfo of the peer we are trying to reach
- *
- * @return peerinfo of the peer who is the first hop in the tunnel
- * NULL on error
- *
- * FIXME use PEER_Id
- */
-struct GNUNET_PeerIdentity *
-tree_get_first_hop (struct CadetTunnelTree *t, GNUNET_PEER_Id peer)
-{
- struct GNUNET_PeerIdentity id;
- struct GNUNET_PeerIdentity *r;
-
- GNUNET_PEER_resolve (peer, &id);
- r = GNUNET_CONTAINER_multihashmap_get (t->first_hops, &id.hashPubKey);
- if (NULL == r)
- {
- struct CadetTunnelTreeNode *n;
-
- n = tree_find_peer (t, peer);
- if (NULL != t->me && NULL != n)
- {
- tree_node_update_first_hops (t, n, NULL);
- r = GNUNET_CONTAINER_multihashmap_get (t->first_hops, &id.hashPubKey);
- GNUNET_assert (NULL != r);
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Tree structure inconsistent! me: %p, n: %p", t->me, n);
- GNUNET_break (0);
- }
- }
-
- return r;
-}
-
-
-/**
- * Find the given peer in the tree.
- *
- * @param tree Tree where to look for the peer.
- * @param peer_id Short ID of the peer to find.
- *
- * @return Pointer to the node of the peer. NULL if not found.
- */
-struct CadetTunnelTreeNode *
-tree_find_peer (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer_id)
-{
- return tree_node_find_peer (tree->root, peer_id);
-}
-
-
-/**
- * Recusively mark peer and children as disconnected, notify client
- *
- * @param tree Tree this node belongs to
- * @param parent Node to be clean, potentially with children
- * @param cb Callback to use to notify about disconnected peers.
- * @param cbcls Closure for cb.
- */
-static void
-tree_mark_peers_disconnected (struct CadetTunnelTree *tree,
- struct CadetTunnelTreeNode *parent,
- CadetTreeCallback cb, void *cbcls)
-{
- struct GNUNET_PeerIdentity *pi;
- struct GNUNET_PeerIdentity id;
- struct CadetTunnelTreeNode *n;
-
- for (n = parent->children_head; NULL != n; n = n->next)
- {
- tree_mark_peers_disconnected (tree, n, cb, cbcls);
- }
- if (CADET_PEER_READY == parent->status)
- {
- if (NULL != cb)
- cb (cbcls, parent->peer);
- parent->status = CADET_PEER_RECONNECTING;
- }
-
- /* Remove and free info about first hop */
- GNUNET_PEER_resolve (parent->peer, &id);
- pi = GNUNET_CONTAINER_multihashmap_get (tree->first_hops, &id.hashPubKey);
- GNUNET_CONTAINER_multihashmap_remove_all (tree->first_hops, &id.hashPubKey);
- if (NULL != pi)
- GNUNET_free (pi);
-}
-
-
-/**
- * Iterate over all children of the local node.
- *
- * @param tree Tree to use. Must have "me" set.
- * @param cb Callback to call over each child.
- * @param cb_cls Closure for @c cb.
- */
-void
-tree_iterate_children (struct CadetTunnelTree *tree, CadetTreeCallback cb,
- void *cb_cls)
-{
- struct CadetTunnelTreeNode *n;
-
- if (NULL == tree->me)
- return;
- for (n = tree->me->children_head; NULL != n; n = n->next)
- {
- cb (cb_cls, n->peer);
- }
-}
-
-
-/**
- * Struct to contain a list of pending nodes when iterating a tree.
- */
-struct CadetTreePendingNode {
-
- /**
- * DLL next.
- */
- struct CadetTreePendingNode *next;
-
- /**
- * DLL prev.
- */
- struct CadetTreePendingNode *prev;
-
- /**
- * Pending node.
- */
- struct CadetTunnelTreeNode *node;
-};
-
-
-/**
- * Iterate over all nodes in the tree.
- *
- * @param tree Tree to use..
- * @param cb Callback to call over each child.
- * @param cb_cls Closure for @c cb.
- *
- * TODO: recursive implementation? (s/heap/stack/g)
- */
-void
-tree_iterate_all (struct CadetTunnelTree *tree,
- CadetWholeTreeCallback cb,
- void *cb_cls)
-{
- struct CadetTunnelTreeNode *parent;
- struct CadetTunnelTreeNode *n;
- struct CadetTreePendingNode *head;
- struct CadetTreePendingNode *tail;
- struct CadetTreePendingNode *pending;
-
- cb (cb_cls, tree->root->peer, 0);
- pending = GNUNET_new (struct CadetTreePendingNode);
- pending->node = tree->root;
- head = tail = NULL;
- GNUNET_CONTAINER_DLL_insert (head, tail, pending);
-
- while (NULL != head)
- {
- pending = head;
- parent = pending->node;
- GNUNET_CONTAINER_DLL_remove (head, tail, pending);
- GNUNET_free (pending);
- for (n = parent->children_head; NULL != n; n = n->next)
- {
- cb (cb_cls, n->peer, parent->peer);
- pending = GNUNET_new (struct CadetTreePendingNode);
- pending->node = n;
- /* Insert_tail: breadth first, Insert: depth first */
- GNUNET_CONTAINER_DLL_insert (head, tail, pending);
- }
- }
-}
-
-
-/**
- * Iterator to count the children in a tree.
- */
-static void
-count_children_cb (void *cls, GNUNET_PEER_Id peer)
-{
- unsigned int *i = cls;
-
- (*i)++;
-}
-
-
-/**
- * Count how many children does the local node have in the tree.
- *
- * @param tree Tree to use. Must have "me" set.
- */
-unsigned int
-tree_count_children (struct CadetTunnelTree *tree)
-{
- unsigned int i;
-
- i = 0;
- tree_iterate_children(tree, &count_children_cb, &i);
- return i;
-}
-
-
-/**
- * Recusively update the info about what is the first hop to reach the node
- *
- * @param tree Tree this nodes belongs to.
- * @param parent_id Short ID from node form which to start updating.
- * @param hop If known, ID of the first hop.
- * If not known, NULL to find out and pass on children.
- */
-void
-tree_update_first_hops (struct CadetTunnelTree *tree, GNUNET_PEER_Id parent_id,
- struct GNUNET_PeerIdentity *hop)
-{
- tree_node_update_first_hops (tree, tree_find_peer (tree, parent_id), hop);
-}
-
-
-/**
- * Delete the current path to the peer, including all now unused relays.
- * The destination peer is NOT destroyed, it is returned in order to either set
- * a new path to it or destroy it explicitly, taking care of it's child nodes.
- *
- * @param t Tunnel tree where to delete the path from.
- * @param peer_id Short ID of the destination peer whose path we want to
remove.
- * @param cb Callback to use to notify about disconnected peers.
- * @param cbcls Closure for cb.
- *
- * @return pointer to the pathless node.
- * NULL when not found
- */
-struct CadetTunnelTreeNode *
-tree_del_path (struct CadetTunnelTree *t, GNUNET_PEER_Id peer_id,
- CadetTreeCallback cb, void *cbcls)
-{
- struct CadetTunnelTreeNode *parent;
- struct CadetTunnelTreeNode *node;
- struct CadetTunnelTreeNode *n;
-
-#if CADET_TREE_DEBUG
- struct GNUNET_PeerIdentity id;
-
- GNUNET_PEER_resolve (peer_id, &id);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Deleting path to %s.\n",
- GNUNET_i2s (&id));
-#endif
- if (NULL == t->root || peer_id == t->root->peer)
- return NULL;
-
- for (n = t->disconnected_head; NULL != n; n = n->next)
- {
- if (n->peer == peer_id)
- {
- /* Was already pathless, waiting for reconnection */
- GNUNET_CONTAINER_DLL_remove (t->disconnected_head, t->disconnected_tail,
- n);
- return n;
- }
- }
- n = tree_find_peer (t, peer_id);
- if (NULL == n)
- return NULL;
- node = n;
-
- parent = n->parent;
- GNUNET_CONTAINER_DLL_remove (parent->children_head, parent->children_tail,
n);
- n->parent = NULL;
-
- while (CADET_PEER_RELAY == parent->status &&
- NULL == parent->children_head)
- {
-#if CADET_TREE_DEBUG
- GNUNET_PEER_resolve (parent->peer, &id);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Deleting node %s.\n",
- GNUNET_i2s (&id));
-#endif
- n = parent->parent;
- if (parent == t->me)
- t->me = NULL;
- tree_node_destroy (parent);
- parent = n;
- }
-#if CADET_TREE_DEBUG
- GNUNET_PEER_resolve (parent->peer, &id);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Not deleted peer %s.\n",
- GNUNET_i2s (&id));
-#endif
-
- tree_mark_peers_disconnected (t, node, cb, cbcls);
-
- return node;
-}
-
-
-/**
- * Return a newly allocated individual path to reach a peer from the local
peer,
- * according to the path tree of some tunnel.
- *
- * @param t Tunnel from which to read the path tree.
- * @param peer Short ID of the destination peer to whom we want a path.
- *
- * @return A newly allocated individual path to reach the destination peer.
- * Path must be destroyed afterwards.
- */
-struct CadetPeerPath *
-tree_get_path_to_peer (struct CadetTunnelTree *t, GNUNET_PEER_Id peer)
-{
- struct CadetTunnelTreeNode *n;
- struct CadetPeerPath *p;
-
- n = tree_find_peer (t, peer);
- if (NULL == n)
- {
- GNUNET_break (0);
- return NULL;
- }
- p = path_new (0);
-
- /* Building the path (inverted!) */
- while (n->peer != 1)
- {
- GNUNET_array_append (p->peers, p->length, n->peer);
- GNUNET_PEER_change_rc (n->peer, 1);
- n = n->parent;
- if (NULL == n)
- {
- GNUNET_break (0);
- path_destroy (p);
- return NULL;
- }
- }
- GNUNET_array_append (p->peers, p->length, 1);
- GNUNET_PEER_change_rc (1, 1);
-
- path_invert (p);
-
- return p;
-}
-
-
-
-/**
- * Integrate a stand alone path into the tunnel tree.
- * If the peer toward which the new path is already in the tree, the peer
- * and its children will be maked as disconnected and the callback
- * will be called on each one of them. They will be maked as online only after
- * receiving a PATH ACK for the new path for each one of them, so the caller
- * should take care of sending a new CREATE PATH message for each disconnected
- * peer.
- *
- * @param t Tunnel where to add the new path.
- * @param p Path to be integrated.
- * @param cb Callback to use to notify about peers temporarily disconnecting.
- * @param cbcls Closure for cb.
- *
- * @return GNUNET_OK in case of success.
- * GNUNET_SYSERR in case of error.
- *
- * TODO: optimize
- * - go backwards on path looking for each peer in the present tree
- * - do not disconnect peers until new path is created & connected
- */
-int
-tree_add_path (struct CadetTunnelTree *t, const struct CadetPeerPath *p,
- CadetTreeCallback cb, void *cbcls)
-{
- struct CadetTunnelTreeNode *parent;
- struct CadetTunnelTreeNode *oldnode;
- struct CadetTunnelTreeNode *n;
- struct CadetTunnelTreeNode *c;
- struct GNUNET_PeerIdentity id;
- int me;
- unsigned int i;
-
-#if CADET_TREE_DEBUG
- GNUNET_PEER_resolve (p->peers[p->length - 1], &id);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "tree: Adding path [%u] towards peer %s.\n", p->length,
- GNUNET_i2s (&id));
-#endif
-
- GNUNET_assert (0 != p->length);
- parent = n = t->root;
- if (n->peer != p->peers[0])
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- if (1 == p->length)
- return GNUNET_OK;
- oldnode = tree_del_path (t, p->peers[p->length - 1], cb, cbcls);
- /* Look for the first node that is not already present in the tree
- *
- * Assuming that the tree is somewhat balanced, O(log n * log N).
- * - Length of the path is expected to be log N (size of whole network).
- * - Each level of the tree is expected to have log n children (size of
tree).
- */
- me = t->root->peer == 1 ? 0 : -1;
- for (i = 1; i < p->length; i++)
- {
-#if CADET_TREE_DEBUG
- GNUNET_PEER_resolve (p->peers[i], &id);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Looking for peer %s.\n",
- GNUNET_i2s (&id));
-#endif
- parent = n;
- if (p->peers[i] == 1)
- me = i;
- for (c = n->children_head; NULL != c; c = c->next)
- {
- if (c->peer == p->peers[i])
- {
-#if CADET_TREE_DEBUG
- GNUNET_PEER_resolve (parent->peer, &id);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "tree: Found in children of %s.\n", GNUNET_i2s (&id));
-#endif
- n = c;
- break;
- }
- }
- /* If we couldn't find a child equal to path[i], we have reached the end
- * of the common path. */
- if (parent == n)
- break;
- }
-#if CADET_TREE_DEBUG
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: All childen visited.\n");
-#endif
- /* Add the rest of the path as a branch from parent. */
- while (i < p->length)
- {
-#if CADET_TREE_DEBUG
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Adding peer %u to %u.\n",
- p->peers[i], parent->peer);
- GNUNET_PEER_resolve (p->peers[i], &id);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Adding peer %s.\n",
- GNUNET_i2s (&id));
- GNUNET_PEER_resolve (parent->peer, &id);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: to %s.\n",
- GNUNET_i2s (&id));
-#endif
-
- if (i == p->length - 1 && NULL != oldnode)
- {
-#if CADET_TREE_DEBUG
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "tree: Putting old node into place.\n");
-#endif
- oldnode->parent = parent;
- GNUNET_CONTAINER_DLL_insert (parent->children_head,
parent->children_tail,
- oldnode);
- tree_node_update_first_hops (t, oldnode, NULL);
- n = oldnode;
- }
- else
- {
-#if CADET_TREE_DEBUG
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Creating new node.\n");
-#endif
- n = tree_node_new (parent, p->peers[i]);
- n->status = CADET_PEER_RELAY;
- }
- if (n->peer == 1)
- {
- t->me = n;
- me = i;
- }
- i++;
- parent = n;
- }
- n->status = CADET_PEER_SEARCHING;
-
- GNUNET_break (-1 != me);
-
- /* Add info about first hop into hashmap. */
- if (-1 != me && me < p->length - 1)
- {
-#if CADET_TREE_DEBUG
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "CADET: finding first hop (own pos %d/%u)\n", me,
- p->length - 1);
-#endif
- GNUNET_PEER_resolve (p->peers[me + 1], &id);
- tree_update_first_hops (t, p->peers[me + 1], &id);
- }
-#if CADET_TREE_DEBUG
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "CADET: was last in path, not updating first hops (%d/%u)\n",
- me, p->length - 1);
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: New node added.\n");
-#endif
- if (NULL == t->me)
- t->me = tree_find_peer (t, 1);
- return GNUNET_OK;
-}
-
-
-/**
- * Notifies a tree that a connection it might be using is broken.
- * Marks all peers down the paths as disconnected and notifies the client.
- *
- * @param t Tree to use.
- * @param p1 Short id of one of the peers (order unimportant)
- * @param p2 Short id of one of the peers (order unimportant)
- * @param cb Function to call for every peer that is marked as disconnected.
- * @param cbcls Closure for cb.
- *
- * @return Short ID of the first disconnected peer in the tree.
- */
-GNUNET_PEER_Id
-tree_notify_connection_broken (struct CadetTunnelTree *t, GNUNET_PEER_Id p1,
- GNUNET_PEER_Id p2, CadetTreeCallback cb,
- void *cbcls)
-{
- struct CadetTunnelTreeNode *n;
- struct CadetTunnelTreeNode *c;
-
- n = tree_find_peer (t, p1);
- if (NULL == n)
- return 0;
- if (NULL != n->parent && n->parent->peer == p2)
- {
- tree_mark_peers_disconnected (t, n, cb, cbcls);
- GNUNET_CONTAINER_DLL_remove (n->parent->children_head,
- n->parent->children_tail, n);
- GNUNET_CONTAINER_DLL_insert (t->disconnected_head, t->disconnected_tail,
n);
- return p1;
- }
- for (c = n->children_head; NULL != c; c = c->next)
- {
- if (c->peer == p2)
- {
- tree_mark_peers_disconnected (t, c, cb, cbcls);
- GNUNET_CONTAINER_DLL_remove (n->children_head, n->children_tail, c);
- GNUNET_CONTAINER_DLL_insert (t->disconnected_head, t->disconnected_tail,
- c);
- return p2;
- }
- }
- return 0;
-}
-
-
-/**
- * Deletes a peer from a tunnel, liberating all unused resources on the path to
- * it. It shouldn't have children, if it has they will be destroyed as well.
- * If the tree is not local and no longer has any paths, the root node will be
- * destroyed and marked as NULL.
- *
- * @param t Tunnel tree to use.
- * @param peer Short ID of the peer to remove from the tunnel tree.
- * @param cb Callback to notify client of disconnected peers.
- * @param cbcls Closure for cb.
- *
- * @return GNUNET_OK or GNUNET_SYSERR
- */
-int
-tree_del_peer (struct CadetTunnelTree *t, GNUNET_PEER_Id peer,
- CadetTreeCallback cb, void *cbcls)
-{
- struct CadetTunnelTreeNode *n;
-
- n = tree_del_path (t, peer, cb, cbcls);
- if (NULL == n)
- {
- GNUNET_break (0);
- return GNUNET_YES;
- }
- tree_node_destroy (n);
- if (NULL == t->root->children_head && t->me != t->root)
- {
- tree_node_destroy (t->root);
- t->root = NULL;
- return GNUNET_NO;
- }
- return GNUNET_YES;
-}
-
-
-
-/**
- * Get the cost of the path relative to the already built tunnel tree.
- *
- * @param t The tunnel tree to which compare.
- * @param path The individual path to reach a peer. It has to start at the
- * root of the tree to be comparable.
- *
- * @return Number of hops to reach destination, UINT_MAX in case the peer is
not
- * in the path.
- *
- * TODO: adapt to allow any start / root combination
- * TODO: take in account state of the nodes
- */
-unsigned int
-tree_get_path_cost (struct CadetTunnelTree *t, struct CadetPeerPath *path)
-{
- struct CadetTunnelTreeNode *n;
- struct CadetTunnelTreeNode *p;
- unsigned int i;
- unsigned int l;
-
- l = path_get_length (path);
- p = t->root;
- if (t->root->peer != path->peers[0])
- {
- GNUNET_break (0);
- return UINT_MAX;
- }
- for (i = 1; i < l; i++)
- {
- for (n = p->children_head; NULL != n; n = n->next)
- {
- if (path->peers[i] == n->peer)
- {
- break;
- }
- }
- if (NULL == n)
- return l - i;
- p = n;
- }
- return l - i;
-}
-
-
-/**
- * Print the tree on stderr
- *
- * @param t The tree
- */
-void
-tree_debug (struct CadetTunnelTree *t)
-{
- tree_node_debug (t->root, 0);
- FPRINTF (stderr, "root: %p\n", t->root);
- FPRINTF (stderr, "me: %p\n", t->me);
-}
-
-
-/**
- * Iterator over hash map peer entries and frees all data in it.
- * Used prior to destroying a hashmap. Makes you miss anonymous functions in C.
- *
- * @param cls closure
- * @param key current key code (will no longer contain valid data!!)
- * @param value value in the hash map (treated as void *)
- * @return GNUNET_YES if we should continue to iterate, GNUNET_NO if not.
- */
-static int
-iterate_free (void *cls, const struct GNUNET_HashCode * key, void *value)
-{
- GNUNET_free (value);
- return GNUNET_YES;
-}
-
-
-/**
- * Destroy the whole tree and free all used memory and Peer_Ids
- *
- * @param t Tree to be destroyed
- */
-void
-tree_destroy (struct CadetTunnelTree *t)
-{
-#if CADET_TREE_DEBUG
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Destroying tree\n");
-#endif
- tree_node_destroy (t->root);
- GNUNET_CONTAINER_multihashmap_iterate (t->first_hops, &iterate_free, NULL);
- GNUNET_CONTAINER_multihashmap_destroy (t->first_hops);
- GNUNET_free (t);
-}
Deleted: gnunet/src/mesh/cadet_tunnel_tree.h
===================================================================
--- gnunet/src/mesh/cadet_tunnel_tree.h 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/cadet_tunnel_tree.h 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,382 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2001 - 2011 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file cadet/cadet_tunnel_tree.h
- * @brief Tunnel tree handling functions
- * @author Bartlomiej Polot
- */
-
-#include "cadet.h"
-
-/******************************************************************************/
-/************************ DATA STRUCTURES
****************************/
-/******************************************************************************/
-
-/**
- * Information regarding a possible path to reach a single peer
- */
-struct CadetPeerPath
-{
-
- /**
- * Linked list
- */
- struct CadetPeerPath *next;
- struct CadetPeerPath *prev;
-
- /**
- * List of all the peers that form the path from origin to target.
- */
- GNUNET_PEER_Id *peers;
-
- /**
- * Number of peers (hops) in the path
- */
- unsigned int length;
-
-};
-
-
-/**
- * Node of path tree for a tunnel
- */
-struct CadetTunnelTreeNode;
-
-
-/**
- * Tree to reach all peers in the tunnel
- */
-struct CadetTunnelTree;
-
-
-/******************************************************************************/
-/************************* FUNCTIONS
*****************************/
-/******************************************************************************/
-
-/**
- * Create a new path.
- *
- * @param length How many hops will the path have.
- *
- * @return A newly allocated path with a peer array of the specified length.
- */
-struct CadetPeerPath *
-path_new (unsigned int length);
-
-
-/**
- * Invert the path.
- *
- * @param path The path to invert.
- */
-void
-path_invert (struct CadetPeerPath *path);
-
-
-/**
- * Duplicate a path, incrementing short peer's rc.
- *
- * @param path The path to duplicate.
- */
-struct CadetPeerPath *
-path_duplicate (struct CadetPeerPath *path);
-
-
-/**
- * Get the length of a path.
- *
- * @param path The path to measure, with the local peer at any point of it.
- *
- * @return Number of hops to reach destination.
- * UINT_MAX in case the peer is not in the path.
- */
-unsigned int
-path_get_length (struct CadetPeerPath *path);
-
-
-/**
- * Destroy the path and free any allocated resources linked to it
- *
- * @param p the path to destroy
- *
- * @return GNUNET_OK on success
- */
-int
-path_destroy (struct CadetPeerPath *p);
-
-
-/******************************************************************************/
-
-/**
- * Iterator over all children of a node.
- *
- * @param cls Closure.
- * @param peer_id Short ID of the peer.
- */
-typedef void (*CadetTreeCallback) (void *cls, GNUNET_PEER_Id peer_id);
-
-
-/**
- * Iterator over all nodes in a tree.
- *
- * @param cls Closure.
- * @param peer_id Short ID of the peer.
- * @param peer_id Short ID of the parent of the peer.
- */
-typedef void (*CadetWholeTreeCallback) (void *cls,
- GNUNET_PEER_Id peer_id,
- GNUNET_PEER_Id parent_id);
-
-/**
- * Create a new tunnel tree associated to a tunnel
- *
- * @param peer A short peer id of the root of the tree
- *
- * @return A newly allocated and initialized tunnel tree
- */
-struct CadetTunnelTree *
-tree_new (GNUNET_PEER_Id peer);
-
-
-/**
- * Set the status of a node.
- *
- * @param tree Tree.
- * @param peer A short peer id of the node.
- * @param status New status to set.
- */
-void
-tree_set_status (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer,
- enum CadetPeerState status);
-
-
-/**
- * Get the status of a node.
- *
- * @param tree Tree whose local id we want to now.
- * @param peer A short peer id of the node.
- *
- * @return Short peer id of local peer.
- */
-enum CadetPeerState
-tree_get_status (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer);
-
-
-/**
- * Get the id of the predecessor of the local node.
- *
- * @param tree Tree whose local id we want to now.
- *
- * @return Short peer id of local peer.
- */
-GNUNET_PEER_Id
-tree_get_predecessor (struct CadetTunnelTree *tree);
-
-
-/**
- * Find the first peer whom to send a packet to go down this path
- *
- * @param t The tunnel tree to use
- * @param peer The peerinfo of the peer we are trying to reach
- *
- * @return peerinfo of the peer who is the first hop in the tunnel
- * NULL on error
- */
-struct GNUNET_PeerIdentity *
-tree_get_first_hop (struct CadetTunnelTree *t, GNUNET_PEER_Id peer);
-
-
-/**
- * Find the given peer in the tree.
- *
- * @param tree Tree where to look for the peer.
- * @param peer_id Peer to find.
- *
- * @return Pointer to the node of the peer. NULL if not found.
- */
-struct CadetTunnelTreeNode *
-tree_find_peer (struct CadetTunnelTree *tree, GNUNET_PEER_Id peer_id);
-
-
-/**
- * Iterate over all children of the local node.
- *
- * @param tree Tree to use. Must have "me" set.
- * @param cb Callback to call over each child.
- * @param cb_cls Closure for @c cb.
- */
-void
-tree_iterate_children (struct CadetTunnelTree *tree,
- CadetTreeCallback cb,
- void *cb_cls);
-
-
-/**
- * Iterate over all nodes in the tree.
- *
- * @param tree Tree to use..
- * @param cb Callback to call over each child.
- * @param cb_cls Closure for @c cb.
- *
- * TODO: recursive implementation? (s/heap/stack/g)
- */
-void
-tree_iterate_all (struct CadetTunnelTree *tree,
- CadetWholeTreeCallback cb,
- void *cb_cls);
-
-/**
- * Count how many children does the local node have in the tree.
- *
- * @param tree Tree to use. Must have "me" set.
- */
-unsigned int
-tree_count_children (struct CadetTunnelTree *tree);
-
-
-/**
- * Recusively update the info about what is the first hop to reach the node
- *
- * @param tree Tree this nodes belongs to.
- * @param parent_id Short ID from node form which to start updating.
- * @param hop If known, ID of the first hop.
- * If not known, NULL to find out and pass on children.
- */
-void
-tree_update_first_hops (struct CadetTunnelTree *tree, GNUNET_PEER_Id parent_id,
- struct GNUNET_PeerIdentity *hop);
-
-/**
- * Delete the current path to the peer, including all now unused relays.
- * The destination peer is NOT destroyed, it is returned in order to either set
- * a new path to it or destroy it explicitly, taking care of it's child nodes.
- *
- * @param t Tunnel tree where to delete the path from.
- * @param peer_id Short ID of the destination peer whose path we want to
remove.
- * @param cb Callback to use to notify about which peers are going to be
- * disconnected.
- * @param cbcls Closure for cb.
- *
- * @return pointer to the pathless node.
- * NULL when not found
- */
-struct CadetTunnelTreeNode *
-tree_del_path (struct CadetTunnelTree *t, GNUNET_PEER_Id peer_id,
- CadetTreeCallback cb, void *cbcls);
-
-
-/**
- * Return a newly allocated individual path to reach a peer from the local
peer,
- * according to the path tree of some tunnel.
- *
- * @param t Tunnel from which to read the path tree
- * @param peer Destination peer to whom we want a path
- *
- * @return A newly allocated individual path to reach the destination peer.
- * Path must be destroyed afterwards.
- */
-struct CadetPeerPath *
-tree_get_path_to_peer (struct CadetTunnelTree *t, GNUNET_PEER_Id peer);
-
-
-/**
- * Integrate a stand alone path into the tunnel tree.
- *
- * @param t Tunnel where to add the new path.
- * @param p Path to be integrated.
- * @param cb Callback to use to notify about peers temporarily disconnecting.
- * @param cbcls Closure for cb.
- *
- * @return GNUNET_OK in case of success.
- * GNUNET_SYSERR in case of error.
- */
-int
-tree_add_path (struct CadetTunnelTree *t, const struct CadetPeerPath *p,
- CadetTreeCallback cb, void *cbcls);
-
-
-/**
- * Notifies a tree that a connection it might be using is broken.
- * Marks all peers down the paths as disconnected and notifies the client.
- *
- * @param t Tree to use.
- * @param p1 Short id of one of the peers (order unimportant)
- * @param p2 Short id of one of the peers (order unimportant)
- * @param cb Function to call for every peer that is marked as disconnected.
- * @param cbcls Closure for cb.
- *
- * @return Short ID of the first disconnected peer in the tree.
- */
-GNUNET_PEER_Id
-tree_notify_connection_broken (struct CadetTunnelTree *t, GNUNET_PEER_Id p1,
- GNUNET_PEER_Id p2, CadetTreeCallback cb,
- void *cbcls);
-
-
-/**
- * Deletes a peer from a tunnel, liberating all unused resources on the path to
- * it. It shouldn't have children, if it has they will be destroyed as well.
- * If the tree is not local and no longer has any paths, the root node will be
- * destroyed and marked as NULL.
- *
- * FIXME: dont destroy the root
- *
- * @param t Tunnel tree to use.
- * @param peer Short ID of the peer to remove from the tunnel tree.
- * @param cb Callback to notify client of disconnected peers.
- * @param cbcls Closure for cb.
- *
- * @return GNUNET_YES if the tunnel still has nodes
- */
-int
-tree_del_peer (struct CadetTunnelTree *t, GNUNET_PEER_Id peer,
- CadetTreeCallback cb, void *cbcls);
-
-
-/**
- * Get the cost of the path relative to the already built tunnel tree
- *
- * @param t The tunnel tree to which compare
- * @param path The individual path to reach a peer
- *
- * @return Number of hops to reach destination, UINT_MAX in case the peer is
not
- * in the path
- */
-unsigned int
-tree_get_path_cost (struct CadetTunnelTree *t, struct CadetPeerPath *path);
-
-
-/**
- * Print the tree on stderr
- *
- * @param t The tree
- */
-void
-tree_debug (struct CadetTunnelTree *t);
-
-
-/**
- * Destroy the whole tree and free all used memory and Peer_Ids
- *
- * @param t Tree to be destroyed
- */
-void
-tree_destroy (struct CadetTunnelTree *t);
Deleted: gnunet/src/mesh/gnunet-cadet-profiler.c
===================================================================
--- gnunet/src/mesh/gnunet-cadet-profiler.c 2014-05-07 12:07:02 UTC (rev
33185)
+++ gnunet/src/mesh/gnunet-cadet-profiler.c 2014-05-07 12:07:16 UTC (rev
33186)
@@ -1,1092 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2011 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-/**
- * @file cadet/gnunet-cadet-profiler.c
- *
- * @brief Profiler for cadet experiments.
- */
-#include <stdio.h>
-#include "platform.h"
-#include "cadet_test_lib.h"
-#include "gnunet_cadet_service.h"
-#include "gnunet_statistics_service.h"
-
-
-#define PING 1
-#define PONG 2
-
-
-/**
- * Paximum ping period in milliseconds. Real period = rand (0, PING_PERIOD)
- */
-#define PING_PERIOD 1000
-
-/**
- * How long until we give up on connecting the peers?
- */
-#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
-
-/**
- * Time to wait for stuff that should be rather fast
- */
-#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
300)
-
-/**
- * Total number of rounds.
- */
-#define number_rounds sizeof(rounds)/sizeof(rounds[0])
-
-/**
- * Ratio of peers active. First round always is 1.0.
- */
-static float rounds[] = {0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.0};
-
-/**
- * Message type for pings.
- */
-struct CadetPingMessage
-{
- /**
- * Header. Type PING/PONG.
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * Message number.
- */
- uint32_t counter;
-
- /**
- * Time the message was sent.
- */
- struct GNUNET_TIME_AbsoluteNBO timestamp;
-
- /**
- * Round number.
- */
- uint32_t round_number;
-};
-
-/**
- * Peer description.
- */
-struct CadetPeer
-{
- /**
- * Testbed Operation (to get peer id, etc).
- */
- struct GNUNET_TESTBED_Operation *op;
-
- /**
- * Peer ID.
- */
- struct GNUNET_PeerIdentity id;
-
- /**
- * Cadet handle for the root peer
- */
- struct GNUNET_CADET_Handle *cadet;
-
- /**
- * Channel handle for the root peer
- */
- struct GNUNET_CADET_Channel *ch;
-
- /**
- * Channel handle for the dest peer
- */
- struct GNUNET_CADET_Channel *incoming_ch;
-
- /**
- * Channel handle for a warmup channel.
- */
- struct GNUNET_CADET_Channel *warmup_ch;
-
- /**
- * Number of payload packes sent
- */
- int data_sent;
-
- /**
- * Number of payload packets received
- */
- int data_received;
-
- /**
- * Is peer up?
- */
- int up;
-
- /**
- * Destinaton to ping.
- */
- struct CadetPeer *dest;
-
- /**
- * Incoming channel for pings.
- */
- struct CadetPeer *incoming;
-
- /**
- * Task to do the next ping.
- */
- GNUNET_SCHEDULER_TaskIdentifier ping_task;
-
- float mean[number_rounds];
- float var[number_rounds];
- unsigned int pongs[number_rounds];
- unsigned int pings[number_rounds];
-
-};
-
-/**
- * Duration of each round.
- */
-static struct GNUNET_TIME_Relative round_time;
-
-/**
- * GNUNET_PeerIdentity -> CadetPeer
- */
-static struct GNUNET_CONTAINER_MultiPeerMap *ids;
-
-/**
- * Testbed peer handles.
- */
-static struct GNUNET_TESTBED_Peer **testbed_handles;
-
-/**
- * Testbed Operation (to get stats).
- */
-static struct GNUNET_TESTBED_Operation *stats_op;
-
-/**
- * Operation to get peer ids.
- */
-struct CadetPeer *peers;
-
-/**
- * Peer ids counter.
- */
-static unsigned int p_ids;
-
-/**
- * Total number of peers.
- */
-static unsigned long long peers_total;
-
-/**
- * Number of currently running peers.
- */
-static unsigned long long peers_running;
-
-/**
- * Number of peers doing pings.
- */
-static unsigned long long peers_pinging;
-
-/**
- * Test context (to shut down).
- */
-static struct GNUNET_CADET_TEST_Context *test_ctx;
-
-/**
- * Task called to shutdown test.
- */
-static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle;
-
-/**
- * Task called to disconnect peers, before shutdown.
- */
-static GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
-
-/**
- * Task to perform tests
- */
-static GNUNET_SCHEDULER_TaskIdentifier test_task;
-
-/**
- * Round number.
- */
-static unsigned int current_round;
-
-/**
- * Do preconnect? (Each peer creates a tunnel to one other peer).
- */
-static int do_warmup;
-
-/**
- * Warmup progress.
- */
-static unsigned int peers_warmup;
-
-/**
- * Flag to notify callbacks not to generate any new traffic anymore.
- */
-static int test_finished;
-
-
-/**
- * START THE TEST ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES.
- *
- * Testcase continues when the root receives confirmation of connected peers,
- * on callback funtion ch.
- *
- * @param cls Closure (unsued).
- * @param tc Task Context.
- */
-static void
-start_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
-
-
-/**
- * Calculate a random delay.
- *
- * @param max Exclusive maximum, in ms.
- *
- * @return A time between 0 a max-1 ms.
- */
-static struct GNUNET_TIME_Relative
-delay_ms_rnd (unsigned int max)
-{
- unsigned int rnd;
-
- rnd = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, max);
- return GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, rnd);
-}
-
-
-/**
- * Get the index of a peer in the peers array.
- *
- * @param peer Peer whose index to get.
- *
- * @return Index of peer in peers.
- */
-static unsigned int
-get_index (struct CadetPeer *peer)
-{
- return peer - peers;
-}
-
-
-/**
- * Show the results of the test (banwidth acheived) and log them to GAUGER
- */
-static void
-show_end_data (void)
-{
- struct CadetPeer *peer;
- unsigned int i;
- unsigned int j;
-
- for (i = 0; i < number_rounds; i++)
- {
- for (j = 0; j < peers_pinging; j++)
- {
- peer = &peers[j];
- FPRINTF (stdout,
- "ROUND %3u PEER %3u: %10.2f / %10.2f, PINGS: %3u, PONGS: %3u\n",
- i, j, peer->mean[i], sqrt (peer->var[i] / (peer->pongs[i] - 1)),
- peer->pings[i], peer->pongs[i]);
- }
- }
-}
-
-
-/**
- * Shut down peergroup, clean up.
- *
- * @param cls Closure (unused).
- * @param tc Task Context.
- */
-static void
-shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Ending test.\n");
- shutdown_handle = GNUNET_SCHEDULER_NO_TASK;
-}
-
-
-/**
- * Disconnect from cadet services af all peers, call shutdown.
- *
- * @param cls Closure (unused).
- * @param tc Task Context.
- */
-static void
-disconnect_cadet_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext
*tc)
-{
- long line = (long) cls;
- unsigned int i;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "disconnecting cadet service, called from line %ld\n", line);
- disconnect_task = GNUNET_SCHEDULER_NO_TASK;
- for (i = 0; i < peers_total; i++)
- {
- if (NULL != peers[i].op)
- GNUNET_TESTBED_operation_done (peers[i].op);
-
- if (peers[i].up != GNUNET_YES)
- continue;
-
- if (NULL != peers[i].ch)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u: channel %p\n", i, peers[i].ch);
- GNUNET_CADET_channel_destroy (peers[i].ch);
- }
- if (NULL != peers[i].warmup_ch)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u: warmup channel %p\n",
- i, peers[i].warmup_ch);
- GNUNET_CADET_channel_destroy (peers[i].warmup_ch);
- }
- if (NULL != peers[i].incoming_ch)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u: incoming channel %p\n",
- i, peers[i].incoming_ch);
- GNUNET_CADET_channel_destroy (peers[i].incoming_ch);
- }
- }
- GNUNET_CADET_TEST_cleanup (test_ctx);
- if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle)
- {
- GNUNET_SCHEDULER_cancel (shutdown_handle);
- }
- shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
-}
-
-
-/**
- * Finish test normally: schedule disconnect and shutdown
- *
- * @param line Line in the code the abort is requested from (__LINE__).
- */
-static void
-abort_test (long line)
-{
- if (disconnect_task != GNUNET_SCHEDULER_NO_TASK)
- {
- GNUNET_SCHEDULER_cancel (disconnect_task);
- disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
- (void *) line);
- }
-}
-
-/**
- * Stats callback. Finish the stats testbed operation and when all stats have
- * been iterated, shutdown the test.
- *
- * @param cls closure
- * @param op the operation that has been finished
- * @param emsg error message in case the operation has failed; will be NULL if
- * operation has executed successfully.
- */
-static void
-stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "... collecting statistics done.\n");
- GNUNET_TESTBED_operation_done (stats_op);
-
- if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
- GNUNET_SCHEDULER_cancel (disconnect_task);
- disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
- (void *) __LINE__);
-
-}
-
-
-/**
- * Process statistic values.
- *
- * @param cls closure
- * @param peer the peer the statistic belong to
- * @param subsystem name of subsystem that created the statistic
- * @param name the name of the datum
- * @param value the current value
- * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
- * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
- */
-static int
-stats_iterator (void *cls, const struct GNUNET_TESTBED_Peer *peer,
- const char *subsystem, const char *name,
- uint64_t value, int is_persistent)
-{
- uint32_t i;
-
- i = GNUNET_TESTBED_get_index (peer);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " STATS %u - %s [%s]: %llu\n",
- i, subsystem, name, value);
-
- return GNUNET_OK;
-}
-
-
-/**
- * Task check that keepalives were sent and received.
- *
- * @param cls Closure (NULL).
- * @param tc Task Context.
- */
-static void
-collect_stats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
- return;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Start collecting statistics...\n");
- stats_op = GNUNET_TESTBED_get_statistics (peers_total, testbed_handles,
- NULL, NULL,
- stats_iterator, stats_cont, NULL);
-}
-
-
-/**
- * @brief Finish profiler normally. Signal finish and start collecting stats.
- *
- * @param cls Closure (unused).
- * @param tc Task context.
- */
-static void
-finish_profiler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
- return;
-
- test_finished = GNUNET_YES;
- show_end_data();
- GNUNET_SCHEDULER_add_now (&collect_stats, NULL);
-}
-
-/**
- * Set the total number of running peers.
- *
- * @param target Desired number of running peers.
- */
-static void
-adjust_running_peers (unsigned int target)
-{
- struct GNUNET_TESTBED_Operation *op;
- unsigned int delta;
- unsigned int run;
- unsigned int i;
- unsigned int r;
-
- GNUNET_assert (target <= peers_total);
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "adjust peers to %u\n", target);
- if (target > peers_running)
- {
- delta = target - peers_running;
- run = GNUNET_YES;
- }
- else
- {
- delta = peers_running - target;
- run = GNUNET_NO;
- }
-
- for (i = 0; i < delta; i++)
- {
- do {
- r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
- peers_total - peers_pinging);
- r += peers_pinging;
- } while (peers[r].up == run || NULL != peers[r].incoming);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "St%s peer %u: %s\n",
- run ? "arting" : "opping", r, GNUNET_i2s (&peers[r].id));
-
- if (GNUNET_SCHEDULER_NO_TASK != peers[r].ping_task)
- GNUNET_SCHEDULER_cancel (peers[r].ping_task);
- peers[r].ping_task = GNUNET_SCHEDULER_NO_TASK;
-
- peers[r].up = run;
-
- if (NULL != peers[r].ch)
- GNUNET_CADET_channel_destroy (peers[r].ch);
- peers[r].ch = NULL;
- if (NULL != peers[r].dest)
- {
- if (NULL != peers[r].dest->incoming_ch)
- GNUNET_CADET_channel_destroy (peers[r].dest->incoming_ch);
- peers[r].dest->incoming_ch = NULL;
- }
-
- op = GNUNET_TESTBED_peer_manage_service (&peers[r], testbed_handles[r],
- "cadet", NULL, NULL, run);
- GNUNET_break (NULL != op);
- peers_running += run ? 1 : -1;
- GNUNET_assert (peers_running > 0);
- }
-}
-
-
-/**
- * @brief Move to next round.
- *
- * @param cls Closure (round #).
- * @param tc Task context.
- */
-static void
-next_rnd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
- return;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "ROUND %ld\n", current_round);
- if (0.0 == rounds[current_round])
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Finishing\n");
- GNUNET_SCHEDULER_add_now (&finish_profiler, NULL);
- return;
- }
- adjust_running_peers (rounds[current_round] * peers_total);
- current_round++;
-
- GNUNET_SCHEDULER_add_delayed (round_time, &next_rnd, NULL);
-}
-
-
-/**
- * Transmit ping callback.
- *
- * @param cls Closure (peer for PING, NULL for PONG).
- * @param size Size of the tranmist buffer.
- * @param buf Pointer to the beginning of the buffer.
- *
- * @return Number of bytes written to buf.
- */
-static size_t
-tmt_rdy_ping (void *cls, size_t size, void *buf);
-
-
-/**
- * Transmit pong callback.
- *
- * @param cls Closure (copy of PING message, to be freed).
- * @param size Size of the buffer we have.
- * @param buf Buffer to copy data to.
- */
-static size_t
-tmt_rdy_pong (void *cls, size_t size, void *buf)
-{
- struct CadetPingMessage *ping = cls;
- struct CadetPingMessage *pong;
-
- if (0 == size || NULL == buf)
- {
- GNUNET_free (ping);
- return 0;
- }
- pong = (struct CadetPingMessage *) buf;
- memcpy (pong, ping, sizeof (*ping));
- pong->header.type = htons (PONG);
-
- GNUNET_free (ping);
- return sizeof (*ping);
-}
-
-
-/**
- * @brief Send a ping to destination
- *
- * @param cls Closure (peer).
- * @param tc Task context.
- */
-static void
-ping (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct CadetPeer *peer = (struct CadetPeer *) cls;
-
- peer->ping_task = GNUNET_SCHEDULER_NO_TASK;
-
- if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0
- || GNUNET_YES == test_finished)
- return;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u -> %u (%u)\n",
- get_index (peer), get_index (peer->dest), peer->data_sent);
-
- GNUNET_CADET_notify_transmit_ready (peer->ch, GNUNET_NO,
- GNUNET_TIME_UNIT_FOREVER_REL,
- sizeof (struct CadetPingMessage),
- &tmt_rdy_ping, peer);
-}
-
-/**
- * @brief Reply with a pong to origin.
- *
- * @param cls Closure (peer).
- * @param tc Task context.
- */
-static void
-pong (struct GNUNET_CADET_Channel *channel, const struct CadetPingMessage
*ping)
-{
- struct CadetPingMessage *copy;
-
- copy = GNUNET_new (struct CadetPingMessage);
- memcpy (copy, ping, sizeof (*ping));
- GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
- GNUNET_TIME_UNIT_FOREVER_REL,
- sizeof (struct CadetPingMessage),
- &tmt_rdy_pong, copy);
-}
-
-
-/**
- * Transmit ping callback
- *
- * @param cls Closure (peer).
- * @param size Size of the buffer we have.
- * @param buf Buffer to copy data to.
- */
-static size_t
-tmt_rdy_ping (void *cls, size_t size, void *buf)
-{
- struct CadetPeer *peer = (struct CadetPeer *) cls;
- struct CadetPingMessage *msg = buf;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tmt_rdy called, filling buffer\n");
- if (size < sizeof (struct CadetPingMessage) || NULL == buf)
- {
- GNUNET_break (GNUNET_YES == test_finished);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "size %u, buf %p, data_sent %u, data_received %u\n",
- size, buf, peer->data_sent, peer->data_received);
-
- return 0;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending: msg %d\n", peer->data_sent);
- msg->header.size = htons (size);
- msg->header.type = htons (PING);
- msg->counter = htonl (peer->data_sent++);
- msg->round_number = htonl (current_round);
- msg->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
- peer->pings[current_round]++;
- peer->ping_task = GNUNET_SCHEDULER_add_delayed (delay_ms_rnd (PING_PERIOD),
- &ping, peer);
-
- return sizeof (struct CadetPingMessage);
-}
-
-
-/**
- * Function is called whenever a PING message is received.
- *
- * @param cls closure (peer #, set from GNUNET_CADET_connect)
- * @param channel connection to the other end
- * @param channel_ctx place to store local state associated with the channel
- * @param message the actual message
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-ping_handler (void *cls, struct GNUNET_CADET_Channel *channel,
- void **channel_ctx,
- const struct GNUNET_MessageHeader *message)
-{
- long n = (long) cls;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%u got PING\n", n);
- GNUNET_CADET_receive_done (channel);
- if (GNUNET_NO == test_finished)
- pong (channel, (struct CadetPingMessage *) message);
-
- return GNUNET_OK;
-}
-
-
-/**
- * Function is called whenever a PONG message is received.
- *
- * @param cls closure (peer #, set from GNUNET_CADET_connect)
- * @param channel connection to the other end
- * @param channel_ctx place to store local state associated with the channel
- * @param message the actual message
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-pong_handler (void *cls, struct GNUNET_CADET_Channel *channel,
- void **channel_ctx,
- const struct GNUNET_MessageHeader *message)
-{
- long n = (long) cls;
- struct CadetPeer *peer;
- struct CadetPingMessage *msg;
- struct GNUNET_TIME_Absolute send_time;
- struct GNUNET_TIME_Relative latency;
- unsigned int r /* Ping round */;
- float delta;
-
- GNUNET_CADET_receive_done (channel);
- peer = &peers[n];
-
- msg = (struct CadetPingMessage *) message;
-
- send_time = GNUNET_TIME_absolute_ntoh (msg->timestamp);
- latency = GNUNET_TIME_absolute_get_duration (send_time);
- r = ntohl (msg->round_number);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u <- %u (%u) latency: %s\n",
- get_index (peer), get_index (peer->dest), ntohl (msg->counter),
- GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO));
-
- /* Online variance calculation */
- peer->pongs[r]++;
- delta = latency.rel_value_us - peer->mean[r];
- peer->mean[r] = peer->mean[r] + delta/peer->pongs[r];
- peer->var[r] += delta * (latency.rel_value_us - peer->mean[r]);
-
- return GNUNET_OK;
-}
-
-
-/**
- * Handlers, for diverse services
- */
-static struct GNUNET_CADET_MessageHandler handlers[] = {
- {&ping_handler, PING, sizeof (struct CadetPingMessage)},
- {&pong_handler, PONG, sizeof (struct CadetPingMessage)},
- {NULL, 0, 0}
-};
-
-
-/**
- * Method called whenever another peer has added us to a channel
- * the other peer initiated.
- *
- * @param cls Closure.
- * @param channel New handle to the channel.
- * @param initiator Peer that started the channel.
- * @param port Port this channel is connected to.
- * @param options channel option flags
- * @return Initial channel context for the channel
- * (can be NULL -- that's not an error).
- */
-static void *
-incoming_channel (void *cls, struct GNUNET_CADET_Channel *channel,
- const struct GNUNET_PeerIdentity *initiator,
- uint32_t port, enum GNUNET_CADET_ChannelOption options)
-{
- long n = (long) cls;
- struct CadetPeer *peer;
-
- peer = GNUNET_CONTAINER_multipeermap_get (ids, initiator);
- GNUNET_assert (NULL != peer);
- if (NULL == peers[n].incoming)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "WARMUP %3u: %u <= %u\n",
- peers_warmup, n, get_index (peer));
- peers_warmup++;
- if (peers_warmup < peers_total)
- return NULL;
- if (GNUNET_SCHEDULER_NO_TASK != test_task)
- {
- GNUNET_SCHEDULER_cancel (test_task);
- test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
- &start_test, NULL);
- }
- return NULL;
- }
- GNUNET_assert (peer == peers[n].incoming);
- GNUNET_assert (peer->dest == &peers[n]);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u <= %u %p\n",
- n, get_index (peer), channel);
- peers[n].incoming_ch = channel;
-
- return NULL;
-}
-
-/**
- * Function called whenever an inbound channel is destroyed. Should clean up
- * any associated state.
- *
- * @param cls closure (set from GNUNET_CADET_connect)
- * @param channel connection to the other end (henceforth invalid)
- * @param channel_ctx place where local state associated
- * with the channel is stored
- */
-static void
-channel_cleaner (void *cls, const struct GNUNET_CADET_Channel *channel,
- void *channel_ctx)
-{
- long n = (long) cls;
- struct CadetPeer *peer = &peers[n];
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Channel %p disconnected at peer %ld\n", channel, n);
- if (peer->ch == channel)
- peer->ch = NULL;
-}
-
-
-/**
- * Select a random peer that has no incoming channel
- *
- * @param peer ID of the peer connecting. NULL if irrelevant (warmup).
- *
- * @return Random peer not yet connected to.
- */
-static struct CadetPeer *
-select_random_peer (struct CadetPeer *peer)
-{
- unsigned int r;
-
- do
- {
- r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, peers_total);
- } while (NULL != peers[r].incoming);
- peers[r].incoming = peer;
-
- return &peers[r];
-}
-
-/**
- * START THE TEST ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES.
- *
- * Testcase continues when the root receives confirmation of connected peers,
- * on callback funtion ch.
- *
- * @param cls Closure (unsued).
- * @param tc Task Context.
- */
-static void
-start_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- enum GNUNET_CADET_ChannelOption flags;
- unsigned long i;
-
- test_task = GNUNET_SCHEDULER_NO_TASK;
- if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
- return;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Start profiler\n");
-
- flags = GNUNET_CADET_OPTION_DEFAULT;
- for (i = 0; i < peers_pinging; i++)
- {
- peers[i].dest = select_random_peer (&peers[i]);
- peers[i].ch = GNUNET_CADET_channel_create (peers[i].cadet, NULL,
- &peers[i].dest->id,
- 1, flags);
- if (NULL == peers[i].ch)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Channel %lu failed\n", i);
- GNUNET_CADET_TEST_cleanup (test_ctx);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u => %u %p\n",
- i, get_index (peers[i].dest), peers[i].ch);
- peers[i].ping_task = GNUNET_SCHEDULER_add_delayed (delay_ms_rnd (2000),
- &ping, &peers[i]);
- }
- peers_running = peers_total;
- if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
- GNUNET_SCHEDULER_cancel (disconnect_task);
- disconnect_task =
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(round_time,
- number_rounds
+ 1),
- &disconnect_cadet_peers,
- (void *) __LINE__);
- GNUNET_SCHEDULER_add_delayed (round_time, &next_rnd, NULL);
-}
-
-
-/**
- * Do warmup: create some channels to spread information about the topology.
- */
-static void
-warmup (void)
-{
- struct CadetPeer *peer;
- unsigned int i;
-
- for (i = 0; i < peers_total; i++)
- {
- peer = select_random_peer (NULL);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "WARMUP %u => %u\n",
- i, get_index (peer));
- peers[i].warmup_ch =
- GNUNET_CADET_channel_create (peers[i].cadet, NULL, &peer->id,
- 1, GNUNET_CADET_OPTION_DEFAULT);
- if (NULL == peers[i].warmup_ch)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Warmup %u failed\n", i);
- GNUNET_CADET_TEST_cleanup (test_ctx);
- return;
- }
- }
-}
-
-/**
- * Callback to be called when the requested peer information is available
- *
- * @param cls the closure from GNUNET_TESTBED_peer_get_information()
- * @param op the operation this callback corresponds to
- * @param pinfo the result; will be NULL if the operation has failed
- * @param emsg error message if the operation has failed;
- * NULL if the operation is successfull
- */
-static void
-peer_id_cb (void *cls,
- struct GNUNET_TESTBED_Operation *op,
- const struct GNUNET_TESTBED_PeerInformation *pinfo,
- const char *emsg)
-{
- long n = (long) cls;
-
- if (NULL == pinfo || NULL != emsg)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg);
- abort_test (__LINE__);
- return;
- }
- peers[n].id = *(pinfo->result.id);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, " %u id: %s\n",
- n, GNUNET_i2s (&peers[n].id));
- GNUNET_break (GNUNET_OK ==
- GNUNET_CONTAINER_multipeermap_put (ids, &peers[n].id,
&peers[n],
-
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
-
- GNUNET_TESTBED_operation_done (peers[n].op);
- peers[n].op = NULL;
-
- p_ids++;
- if (p_ids < peers_total)
- return;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got all IDs, starting profiler\n");
- if (do_warmup)
- {
- struct GNUNET_TIME_Relative delay;
-
- warmup();
- delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
- 100 * peers_total);
- test_task = GNUNET_SCHEDULER_add_delayed (delay, &start_test, NULL);
- return; /* start_test from incoming_channel */
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Starting in a second...\n");
- test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
- &start_test, NULL);
-}
-
-/**
- * test main: start test when all peers are connected
- *
- * @param cls Closure.
- * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
- * @param num_peers Number of peers that are running.
- * @param testbed_peers Array of peers.
- * @param cadetes Handle to each of the CADETs of the peers.
- */
-static void
-tmain (void *cls,
- struct GNUNET_CADET_TEST_Context *ctx,
- unsigned int num_peers,
- struct GNUNET_TESTBED_Peer **testbed_peers,
- struct GNUNET_CADET_Handle **cadetes)
-{
- unsigned long i;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n");
- test_ctx = ctx;
- GNUNET_assert (peers_total == num_peers);
- peers_running = num_peers;
- testbed_handles = testbed_peers;
- disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
- &disconnect_cadet_peers,
- (void *) __LINE__);
- shutdown_handle = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
- &shutdown_task, NULL);
- for (i = 0; i < peers_total; i++)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requesting id %ld\n", i);
- peers[i].up = GNUNET_YES;
- peers[i].cadet = cadetes[i];
- peers[i].op =
- GNUNET_TESTBED_peer_get_information (testbed_handles[i],
- GNUNET_TESTBED_PIT_IDENTITY,
- &peer_id_cb, (void *) i);
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "requested peer ids\n");
- /* Continues from pi_cb -> do_test */
-}
-
-
-/**
- * Main: start profiler.
- */
-int
-main (int argc, char *argv[])
-{
- static uint32_t ports[2];
- const char *config_file;
-
- config_file = ".profiler.conf";
-
- if (4 > argc)
- {
- fprintf (stderr, "usage: %s ROUND_TIME PEERS PINGS [DO_WARMUP]\n",
argv[0]);
- fprintf (stderr, "example: %s 30s 16 1 Y\n", argv[0]);
- return 1;
- }
-
- if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_relative (argv[1],
&round_time))
- {
- fprintf (stderr, "%s is not a valid time\n", argv[1]);
- return 1;
- }
-
- peers_total = atoll (argv[2]);
- if (2 > peers_total)
- {
- fprintf (stderr, "%s peers is not valid (> 2)\n", argv[1]);
- return 1;
- }
- peers = GNUNET_malloc (sizeof (struct CadetPeer) * peers_total);
-
- peers_pinging = atoll (argv[3]);
-
- if (peers_total < 2 * peers_pinging)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "not enough peers, total should be > 2 * peers_pinging\n");
- return 1;
- }
-
- do_warmup = (5 > argc || argv[4][0] != 'N');
-
- ids = GNUNET_CONTAINER_multipeermap_create (2 * peers_total, GNUNET_YES);
- GNUNET_assert (NULL != ids);
- p_ids = 0;
- test_finished = GNUNET_NO;
- ports[0] = 1;
- ports[1] = 0;
- GNUNET_CADET_TEST_run ("cadet-profiler", config_file, peers_total,
- &tmain, NULL, /* tmain cls */
- &incoming_channel, &channel_cleaner,
- handlers, ports);
- GNUNET_free (peers);
-
- return 0;
-}
-
-/* end of gnunet-cadet-profiler.c */
-
Deleted: gnunet/src/mesh/gnunet-cadet.c
===================================================================
--- gnunet/src/mesh/gnunet-cadet.c 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/gnunet-cadet.c 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,851 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2012 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file cadet/gnunet-cadet.c
- * @brief Print information about cadet tunnels and peers.
- * @author Bartlomiej Polot
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_cadet_service.h"
-#include "cadet.h"
-
-
-/**
- * Option -m.
- */
-static int monitor_connections;
-
-/**
- * Option -P.
- */
-static int request_peers;
-
-/**
- * Option --peer
- */
-static char *peer_id;
-
-/**
- * Option -T.
- */
-static int request_tunnels;
-
-/**
- * Option --tunnel
- */
-static char *tunnel_id;
-
-/**
- * Option --connection
- */
-static char *conn_id;
-
-/**
- * Option --channel
- */
-static char *channel_id;
-
-/**
- * Port to listen on (-p).
- */
-static uint32_t listen_port;
-
-/**
- * Request echo service
- */
-int echo;
-
-/**
- * Time of last echo request.
- */
-struct GNUNET_TIME_Absolute echo_time;
-
-/**
- * Task for next echo request.
- */
-GNUNET_SCHEDULER_TaskIdentifier echo_task;
-
-/**
- * Peer to connect to.
- */
-static char *target_id;
-
-/**
- * Port to connect to
- */
-static uint32_t target_port;
-
-/**
- * Data pending in netcat mode.
- */
-size_t data_size;
-
-
-/**
- * Cadet handle.
- */
-static struct GNUNET_CADET_Handle *mh;
-
-/**
- * Channel handle.
- */
-static struct GNUNET_CADET_Channel *ch;
-
-/**
- * Shutdown task handle.
- */
-GNUNET_SCHEDULER_TaskIdentifier sd;
-
-
-
-static void
-listen_stdio (void);
-
-
-
-/**
- * Task run in monitor mode when the user presses CTRL-C to abort.
- * Stops monitoring activity.
- *
- * @param cls Closure (unused).
- * @param tc scheduler context
- */
-static void
-shutdown_task (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
- if (NULL != ch)
- {
- GNUNET_CADET_channel_destroy (ch);
- ch = NULL;
- }
- if (NULL != mh)
- {
- GNUNET_CADET_disconnect (mh);
- mh = NULL;
- }
-}
-
-
-/**
- * Function called to notify a client about the connection
- * begin ready to queue more data. "buf" will be
- * NULL and "size" zero if the connection was closed for
- * writing in the meantime.
- *
- * FIXME
- *
- * @param cls closure
- * @param size number of bytes available in buf
- * @param buf where the callee should write the message
- * @return number of bytes written to buf
- */
-size_t
-data_ready (void *cls, size_t size, void *buf)
-{
- struct GNUNET_MessageHeader *msg;
- size_t total_size;
-
- if (NULL == buf || 0 == size)
- {
- GNUNET_SCHEDULER_shutdown();
- return 0;
- }
-
- total_size = data_size + sizeof (struct GNUNET_MessageHeader);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending %u bytes\n", data_size);
- GNUNET_assert (size >= total_size);
-
- msg = buf;
- msg->size = htons (total_size);
- msg->type = htons (GNUNET_MESSAGE_TYPE_CADET_CLI);
- memcpy (&msg[1], cls, data_size);
- if (GNUNET_NO == echo)
- {
- listen_stdio ();
- }
- else
- {
- echo_time = GNUNET_TIME_absolute_get ();
- }
-
- return total_size;
-}
-
-
-/**
- * Task run in monitor mode when the user presses CTRL-C to abort.
- * Stops monitoring activity.
- *
- * @param cls Closure (unused).
- * @param tc scheduler context
- */
-static void
-read_stdio (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- static char buf[60000];
-
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- {
- return;
- }
-
- data_size = read (0, buf, 60000);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "stdio read %u bytes\n", data_size);
- if (data_size < 1)
- {
- GNUNET_SCHEDULER_shutdown();
- return;
- }
- GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
- GNUNET_TIME_UNIT_FOREVER_REL,
- data_size
- + sizeof (struct GNUNET_MessageHeader),
- &data_ready, buf);
-}
-
-
-/**
- * Start listening to stdin
- */
-static void
-listen_stdio (void)
-{
- struct GNUNET_NETWORK_FDSet *rs;
-
- rs = GNUNET_NETWORK_fdset_create ();
- GNUNET_NETWORK_fdset_set_native (rs, 0);
- GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
- GNUNET_TIME_UNIT_FOREVER_REL,
- rs, NULL,
- &read_stdio, NULL);
- GNUNET_NETWORK_fdset_destroy (rs);
-}
-
-
-/**
- * Function called whenever a channel is destroyed. Should clean up
- * any associated state.
- *
- * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
- *
- * @param cls closure (set from #GNUNET_CADET_connect)
- * @param channel connection to the other end (henceforth invalid)
- * @param channel_ctx place where local state associated
- * with the channel is stored
- */
-static void
-channel_ended (void *cls,
- const struct GNUNET_CADET_Channel *channel,
- void *channel_ctx)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel ended!\n");
- GNUNET_break (channel == ch);
- ch = NULL;
- GNUNET_SCHEDULER_shutdown ();
-}
-
-
-/**
- * Method called whenever another peer has added us to a channel
- * the other peer initiated.
- * Only called (once) upon reception of data with a message type which was
- * subscribed to in #GNUNET_CADET_connect.
- *
- * A call to #GNUNET_CADET_channel_destroy causes te channel to be ignored. In
- * this case the handler MUST return NULL.
- *
- * @param cls closure
- * @param channel new handle to the channel
- * @param initiator peer that started the channel
- * @param port Port this channel is for.
- * @param options CadetOption flag field, with all active option bits set to 1.
- *
- * @return initial channel context for the channel
- * (can be NULL -- that's not an error)
- */
-static void *
-channel_incoming (void *cls,
- struct GNUNET_CADET_Channel * channel,
- const struct GNUNET_PeerIdentity * initiator,
- uint32_t port, enum GNUNET_CADET_ChannelOption options)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Incoming channel %p on port %u\n",
- channel, port);
- if (NULL != ch)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "A channel already exists\n");
- return NULL;
- }
- if (0 == listen_port)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not listening to channels\n");
- return NULL;
- }
- ch = channel;
- if (GNUNET_NO == echo)
- {
- listen_stdio ();
- return NULL;
- }
- data_size = 0;
- return NULL;
-}
-
-/**
- * @brief Send an echo request to the remote peer.
- *
- * @param cls Closure (NULL).
- * @param tc Task context.
- */
-static void
-send_echo (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) || NULL == ch)
- return;
-
- GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
- GNUNET_TIME_UNIT_FOREVER_REL,
- sizeof (struct GNUNET_MessageHeader),
- &data_ready, NULL);
-}
-
-
-
-/**
- * Call CADET's monitor API, get info of one connection.
- *
- * @param cls Closure (unused).
- * @param tc TaskContext
- */
-static void
-create_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct GNUNET_PeerIdentity pid;
- enum GNUNET_CADET_ChannelOption opt;
-
- GNUNET_assert (NULL == ch);
-
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
- strlen (target_id),
- &pid.public_key))
- {
- FPRINTF (stderr,
- _("Invalid target `%s'\n"),
- target_id);
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to `%s'\n", target_id);
- opt = GNUNET_CADET_OPTION_DEFAULT | GNUNET_CADET_OPTION_RELIABLE;
- ch = GNUNET_CADET_channel_create (mh, NULL, &pid, target_port, opt);
- if (GNUNET_NO == echo)
- listen_stdio ();
- else
- GNUNET_SCHEDULER_add_now (send_echo, NULL);
-}
-
-
-/**
- * Function called whenever a message is received.
- *
- * Each time the function must call #GNUNET_CADET_receive_done on the channel
- * in order to receive the next message. This doesn't need to be immediate:
- * can be delayed if some processing is done on the message.
- *
- * @param cls Closure (set from #GNUNET_CADET_connect).
- * @param channel Connection to the other end.
- * @param channel_ctx Place to store local state associated with the channel.
- * @param message The actual message.
- * @return #GNUNET_OK to keep the channel open,
- * #GNUNET_SYSERR to close it (signal serious error).
- */
-static int
-data_callback (void *cls,
- struct GNUNET_CADET_Channel *channel,
- void **channel_ctx,
- const struct GNUNET_MessageHeader *message)
-{
- uint16_t len;
- ssize_t done;
- uint16_t off;
- const char *buf;
- GNUNET_break (ch == channel);
-
- if (GNUNET_YES == echo)
- {
- if (0 != listen_port)
- {
- /* Just listening to echo incoming messages*/
- GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
- GNUNET_TIME_UNIT_FOREVER_REL,
- sizeof (struct GNUNET_MessageHeader),
- &data_ready, NULL);
- return GNUNET_OK;
- }
- else
- {
- struct GNUNET_TIME_Relative latency;
-
- latency = GNUNET_TIME_absolute_get_duration (echo_time);
- echo_time = GNUNET_TIME_UNIT_FOREVER_ABS;
- FPRINTF (stdout, "time: %s\n",
- GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO));
- echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
- &send_echo, NULL);
- }
- }
-
- len = ntohs (message->size) - sizeof (*message);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u bytes\n", len);
- buf = (const char *) &message[1];
- off = 0;
- while (off < len)
- {
- done = write (1, &buf[off], len - off);
- if (done <= 0)
- {
- if (-1 == done)
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
- "write");
- return GNUNET_SYSERR;
- }
- off += done;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Method called to retrieve information about all peers in CADET, called
- * once per peer.
- *
- * After last peer has been reported, an additional call with NULL is done.
- *
- * @param cls Closure.
- * @param peer Peer, or NULL on "EOF".
- * @param tunnel Do we have a tunnel towards this peer?
- * @param n_paths Number of known paths towards this peer.
- * @param best_path How long is the best path?
- * (0 = unknown, 1 = ourselves, 2 = neighbor)
- */
-static void
-peers_callback (void *cls, const struct GNUNET_PeerIdentity *peer,
- int tunnel, unsigned int n_paths, unsigned int best_path)
-{
- if (NULL == peer)
- {
- if (GNUNET_YES != monitor_connections)
- {
- GNUNET_SCHEDULER_shutdown();
- }
- return;
- }
- FPRINTF (stdout, "%s tunnel: %c, paths: %u\n",
- GNUNET_i2s_full (peer), tunnel ? 'Y' : 'N', n_paths);
-}
-
-/**
- * Method called to retrieve information about a specific peer
- * known to the service.
- *
- * @param cls Closure.
- * @param peer Peer ID.
- * @param tunnel Do we have a tunnel towards this peer? #GNUNET_YES/#GNUNET_NO
- * @param neighbor Is this a direct neighbor? #GNUNET_YES/#GNUNET_NO
- * @param n_paths Number of paths known towards peer.
- * @param paths Array of PEER_IDs representing all paths to reach the peer.
- * Each path starts with the local peer.
- * Each path ends with the destination peer (given in @c peer).
- */
-void
-peer_callback (void *cls,
- const struct GNUNET_PeerIdentity *peer,
- int tunnel,
- int neighbor,
- unsigned int n_paths,
- struct GNUNET_PeerIdentity *paths)
-{
-}
-
-
-/**
- * Method called to retrieve information about all tunnels in CADET.
- *
- * @param cls Closure.
- * @param peer Destination peer.
- * @param channels Number of channels.
- * @param connections Number of connections.
- * @param estate Encryption state.
- * @param cstate Connectivity state.
- */
-void
-tunnels_callback (void *cls,
- const struct GNUNET_PeerIdentity *peer,
- unsigned int channels,
- unsigned int connections,
- uint16_t estate,
- uint16_t cstate)
-{
- if (NULL == peer)
- {
- if (GNUNET_YES != monitor_connections)
- {
- GNUNET_SCHEDULER_shutdown();
- }
- return;
- }
- FPRINTF (stdout, "%s [ENC: %u, CON: %u] CHs: %u, CONNs: %u\n",
- GNUNET_i2s_full (peer), estate, cstate, channels, connections);
-}
-
-
-/**
- * Method called to retrieve information about a specific tunnel the cadet peer
- * has established, o`r is trying to establish.
- *
- * @param cls Closure.
- * @param peer Peer towards whom the tunnel is directed.
- * @param n_channels Number of channels.
- * @param n_connections Number of connections.
- * @param channels Channels.
- * @param connections Connections.
- * @param estate Encryption status.
- * @param cstate Connectivity status.
- */
-void
-tunnel_callback (void *cls,
- const struct GNUNET_PeerIdentity *peer,
- unsigned int n_channels,
- unsigned int n_connections,
- uint32_t *channels,
- struct GNUNET_CADET_Hash *connections,
- unsigned int estate,
- unsigned int cstate)
-{
- unsigned int i;
-
- if (NULL != peer)
- {
- FPRINTF (stdout, "Tunnel %s\n", GNUNET_i2s_full (peer));
- FPRINTF (stdout, "- %u channels\n", n_channels);
- for (i = 0; i < n_channels; i++)
- FPRINTF (stdout, " %u\n", channels[i]);
- FPRINTF (stdout, "- %u connections\n", n_connections);
- for (i = 0; i < n_connections; i++)
- FPRINTF (stdout, " %s\n", GM_h2s (&connections[i]));
- FPRINTF (stdout, "- enc state: %u\n", estate);
- FPRINTF (stdout, "- con state: %u\n", cstate);
- }
- if (GNUNET_YES != monitor_connections)
- {
- GNUNET_SCHEDULER_shutdown();
- }
- return;
-
-}
-
-
-/**
- * Call CADET's meta API, get all peers known to a peer.
- *
- * @param cls Closure (unused).
- * @param tc TaskContext
- */
-static void
-get_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
- return;
- }
- GNUNET_CADET_get_peers (mh, &peers_callback, NULL);
-}
-
-
-/**
- * Call CADET's monitor API, get info of one peer.
- *
- * @param cls Closure (unused).
- * @param tc TaskContext
- */
-static void
-show_peer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct GNUNET_PeerIdentity pid;
-
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id,
- strlen (peer_id),
- &pid.public_key))
- {
- fprintf (stderr,
- _("Invalid peer ID `%s'\n"),
- peer_id);
- GNUNET_SCHEDULER_shutdown();
- return;
- }
- GNUNET_CADET_get_peer (mh, &pid, peer_callback, NULL);
-}
-
-/**
- * Call CADET's meta API, get all tunnels known to a peer.
- *
- * @param cls Closure (unused).
- * @param tc TaskContext
- */
-static void
-get_tunnels (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
- return;
- }
- GNUNET_CADET_get_tunnels (mh, &tunnels_callback, NULL);
-}
-
-
-/**
- * Call CADET's monitor API, get info of one tunnel.
- *
- * @param cls Closure (unused).
- * @param tc TaskContext
- */
-static void
-show_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct GNUNET_PeerIdentity pid;
-
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_public_key_from_string (tunnel_id,
- strlen (tunnel_id),
- &pid.public_key))
- {
- fprintf (stderr,
- _("Invalid tunnel owner `%s'\n"),
- tunnel_id);
- GNUNET_SCHEDULER_shutdown();
- return;
- }
- GNUNET_CADET_get_tunnel (mh, &pid, tunnel_callback, NULL);
-}
-
-
-/**
- * Call CADET's monitor API, get info of one channel.
- *
- * @param cls Closure (unused).
- * @param tc TaskContext
- */
-static void
-show_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
-
-}
-
-
-/**
- * Call CADET's monitor API, get info of one connection.
- *
- * @param cls Closure (unused).
- * @param tc TaskContext
- */
-static void
-show_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
-
-}
-
-
-/**
- * Main function that will be run by the scheduler.
- *
- * @param cls closure
- * @param args remaining command-line arguments
- * @param cfgfile name of the configuration file used (for saving, can be
NULL!)
- * @param cfg configuration
- */
-static void
-run (void *cls, char *const *args, const char *cfgfile,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- GNUNET_CADET_InboundChannelNotificationHandler *newch = NULL;
- GNUNET_CADET_ChannelEndHandler *endch = NULL;
- static const struct GNUNET_CADET_MessageHandler handlers[] = {
- {&data_callback, GNUNET_MESSAGE_TYPE_CADET_CLI, 0},
- {NULL, 0, 0} /* FIXME add option to monitor msg types */
- };
- static uint32_t *ports = NULL;
- /* FIXME add option to monitor apps */
-
- target_id = args[0];
- target_port = args[0] && args[1] ? atoi(args[1]) : 0;
- if ( (0 != (request_peers | request_tunnels)
- || 0 != monitor_connections
- || NULL != tunnel_id
- || NULL != conn_id
- || NULL != channel_id)
- && target_id != NULL)
- {
- FPRINTF (stderr,
- _("You must NOT give a TARGET"
- "when using 'request all' options\n"));
- return;
- }
-
- if (NULL != target_id)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Creating channel to %s\n",
- target_id);
- GNUNET_SCHEDULER_add_now (&create_channel, NULL);
- endch = &channel_ended;
- }
- else if (0 != listen_port)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Listen\n");
- newch = &channel_incoming;
- endch = &channel_ended;
- ports = GNUNET_malloc (sizeof (uint32_t) * 2);
- ports[0] = listen_port;
- }
- else if (NULL != peer_id)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show peer\n");
- GNUNET_SCHEDULER_add_now (&show_peer, NULL);
- }
- else if (NULL != tunnel_id)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show tunnel\n");
- GNUNET_SCHEDULER_add_now (&show_tunnel, NULL);
- }
- else if (NULL != channel_id)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show channel\n");
- GNUNET_SCHEDULER_add_now (&show_channel, NULL);
- }
- else if (NULL != conn_id)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show connection\n");
- GNUNET_SCHEDULER_add_now (&show_connection, NULL);
- }
- else if (GNUNET_YES == request_peers)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all peers\n");
- GNUNET_SCHEDULER_add_now (&get_peers, NULL);
- }
- else if (GNUNET_YES == request_tunnels)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all tunnels\n");
- GNUNET_SCHEDULER_add_now (&get_tunnels, NULL);
- }
- else
- {
- FPRINTF (stderr, "No action requested\n");
- return;
- }
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to cadet\n");
- mh = GNUNET_CADET_connect (cfg,
- NULL, /* cls */
- newch, /* new channel */
- endch, /* cleaner */
- handlers,
- ports);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done\n");
- if (NULL == mh)
- GNUNET_SCHEDULER_add_now (shutdown_task, NULL);
- else
- sd = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
- shutdown_task, NULL);
-
-}
-
-
-/**
- * The main function to obtain peer information.
- *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
- */
-int
-main (int argc, char *const *argv)
-{
- int res;
- const char helpstr[] = "Create channels and retreive info about cadets
status.";
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-// {'a', "channel", "TUNNEL_ID:CHANNEL_ID",
-// gettext_noop ("provide information about a particular channel"),
-// GNUNET_YES, &GNUNET_GETOPT_set_string, &channel_id},
- {'C', "connection", "CONNECTION_ID",
- gettext_noop ("provide information about a particular connection"),
- GNUNET_YES, &GNUNET_GETOPT_set_string, &conn_id},
- {'e', "echo", NULL,
- gettext_noop ("activate echo mode"),
- GNUNET_NO, &GNUNET_GETOPT_set_one, &echo},
-// {'m', "monitor", NULL,
-// gettext_noop ("provide information about all events (continuously)"),
-// GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor_mode},
- {'o', "open-port", NULL,
- gettext_noop ("port to listen to (default; 0)"),
- GNUNET_YES, &GNUNET_GETOPT_set_uint, &listen_port},
- {'p', "peer", "PEER_ID",
- gettext_noop ("provide information about a patricular peer"),
- GNUNET_YES, &GNUNET_GETOPT_set_string, &peer_id},
- {'P', "peers", NULL,
- gettext_noop ("provide information about all peers"),
- GNUNET_NO, &GNUNET_GETOPT_set_one, &request_peers},
- {'t', "tunnel", "TUNNEL_ID",
- gettext_noop ("provide information about a particular tunnel"),
- GNUNET_YES, &GNUNET_GETOPT_set_string, &tunnel_id},
- {'T', "tunnels", NULL,
- gettext_noop ("provide information about all tunnels"),
- GNUNET_NO, &GNUNET_GETOPT_set_one, &request_tunnels},
-
- GNUNET_GETOPT_OPTION_END
- };
-
- monitor_connections = GNUNET_NO;
-
- if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
- return 2;
-
- res = GNUNET_PROGRAM_run (argc, argv, "gnunet-cadet (OPTIONS | TARGET PORT)",
- gettext_noop (helpstr),
- options, &run, NULL);
-
- GNUNET_free ((void *) argv);
-
- if (GNUNET_OK == res)
- return 0;
- else
- return 1;
-}
-
-/* end of gnunet-cadet.c */
Deleted: gnunet/src/mesh/gnunet-service-cadet.c
===================================================================
--- gnunet/src/mesh/gnunet-service-cadet.c 2014-05-07 12:07:02 UTC (rev
33185)
+++ gnunet/src/mesh/gnunet-service-cadet.c 2014-05-07 12:07:16 UTC (rev
33186)
@@ -1,181 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2001-2013 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet.c
- * @brief GNUnet CADET service with encryption
- * @author Bartlomiej Polot
- *
- * FIXME in progress:
- * - rekey - reliability interaction
- * - channel retransmit timing
- *
- * TODO:
- * - relay corking down to core
- * - set ttl relative to path length
- * TODO END
- *
- * Dictionary:
- * - peer: other cadet instance. If there is direct connection it's a neighbor.
- * - tunnel: encrypted connection to a peer, neighbor or not.
- * - channel: connection between two clients, on the same or different peers.
- * have properties like reliability.
- * - path: series of directly connected peer from one peer to another.
- * - connection: path which is being used in a tunnel.
- */
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "cadet.h"
-#include "gnunet_statistics_service.h"
-
-#include "gnunet-service-cadet_local.h"
-#include "gnunet-service-cadet_channel.h"
-#include "gnunet-service-cadet_connection.h"
-#include "gnunet-service-cadet_tunnel.h"
-#include "gnunet-service-cadet_dht.h"
-#include "gnunet-service-cadet_peer.h"
-#include "gnunet-service-cadet_hello.h"
-
-
-/******************************************************************************/
-/*********************** GLOBAL VARIABLES
****************************/
-/******************************************************************************/
-
-/****************************** Global variables
******************************/
-
-/**
- * Handle to the statistics service.
- */
-struct GNUNET_STATISTICS_Handle *stats;
-
-/**
- * Local peer own ID (memory efficient handle).
- */
-GNUNET_PEER_Id myid;
-
-/**
- * Local peer own ID (full value).
- */
-struct GNUNET_PeerIdentity my_full_id;
-
-
-/**
- * Signal that shutdown is happening: prevent recover measures.
- */
-int shutting_down;
-
-/*************************** Static global variables
**************************/
-
-/**
- * Own private key.
- */
-static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
-
-
-/******************************************************************************/
-/************************ MAIN FUNCTIONS
****************************/
-/******************************************************************************/
-
-/**
- * Task run during shutdown.
- *
- * @param cls unused
- * @param tc unused
- */
-static void
-shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutting down\n");
-
- shutting_down = GNUNET_YES;
-
- GML_shutdown ();
- GMH_shutdown ();
- GMC_shutdown ();
- GMT_shutdown ();
- GMD_shutdown ();
- GMP_shutdown ();
-
- GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
- stats = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shut down\n");
-}
-
-
-/**
- * Process cadet requests.
- *
- * @param cls closure
- * @param server the initialized server
- * @param c configuration to use
- */
-static void
-run (void *cls, struct GNUNET_SERVER_Handle *server,
- const struct GNUNET_CONFIGURATION_Handle *c)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting to run\n");
-
- stats = GNUNET_STATISTICS_create ("cadet", c);
-
- /* Scheduled the task to clean up when shutdown is called */
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
- NULL);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "reading key\n");
- my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
- GNUNET_assert (NULL != my_private_key);
- GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_full_id.public_key);
- myid = GNUNET_PEER_intern (&my_full_id);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "STARTING SERVICE (CADET) for peer [%s]\n",
- GNUNET_i2s (&my_full_id));
-
- GML_init (server); /* Local clients */
- GMH_init (c); /* Hellos */
- GMC_init (c); /* Connections */
- GMP_init (c); /* Peers */
- GMD_init (c); /* DHT */
- GMT_init (c, my_private_key); /* Tunnels */
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cadet service running\n");
-}
-
-
-/**
- * The main function for the cadet service.
- *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
- */
-int
-main (int argc, char *const *argv)
-{
- int ret;
- int r;
-
- shutting_down = GNUNET_NO;
- r = GNUNET_SERVICE_run (argc, argv, "cadet", GNUNET_SERVICE_OPTION_NONE,
&run,
- NULL);
- GNUNET_free (my_private_key);
- ret = (GNUNET_OK == r) ? 0 : 1;
-
- return ret;
-}
Deleted: gnunet/src/mesh/gnunet-service-cadet_channel.c
===================================================================
--- gnunet/src/mesh/gnunet-service-cadet_channel.c 2014-05-07 12:07:02 UTC
(rev 33185)
+++ gnunet/src/mesh/gnunet-service-cadet_channel.c 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -1,2432 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2013 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#include "gnunet_statistics_service.h"
-
-#include "cadet.h"
-#include "cadet_protocol.h"
-
-#include "gnunet-service-cadet_channel.h"
-#include "gnunet-service-cadet_local.h"
-#include "gnunet-service-cadet_tunnel.h"
-#include "gnunet-service-cadet_peer.h"
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-chn",__VA_ARGS__)
-
-#define CADET_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(\
- GNUNET_TIME_UNIT_MILLISECONDS, 250)
-#define CADET_RETRANSMIT_MARGIN 4
-
-
-/**
- * All the states a connection can be in.
- */
-enum CadetChannelState
-{
- /**
- * Uninitialized status, should never appear in operation.
- */
- CADET_CHANNEL_NEW,
-
- /**
- * Connection create message sent, waiting for ACK.
- */
- CADET_CHANNEL_SENT,
-
- /**
- * Connection confirmed, ready to carry traffic.
- */
- CADET_CHANNEL_READY,
-};
-
-
-/**
- * Info holder for channel messages in queues.
- */
-struct CadetChannelQueue
-{
- /**
- * Tunnel Queue.
- */
- struct CadetTunnel3Queue *tq;
-
- /**
- * Message type (DATA/DATA_ACK)
- */
- uint16_t type;
-
- /**
- * Message copy (for DATAs, to start retransmission timer)
- */
- struct CadetReliableMessage *copy;
-
- /**
- * Reliability (for DATA_ACKs, to access rel->ack_q)
- */
- struct CadetChannelReliability *rel;
-};
-
-
-/**
- * Info needed to retry a message in case it gets lost.
- */
-struct CadetReliableMessage
-{
- /**
- * Double linked list, FIFO style
- */
- struct CadetReliableMessage *next;
- struct CadetReliableMessage *prev;
-
- /**
- * Type of message (payload, channel management).
- */
- int16_t type;
-
- /**
- * Tunnel Reliability queue this message is in.
- */
- struct CadetChannelReliability *rel;
-
- /**
- * ID of the message (ACK needed to free)
- */
- uint32_t mid;
-
- /**
- * Tunnel Queue.
- */
- struct CadetChannelQueue *chq;
-
- /**
- * When was this message issued (to calculate ACK delay)
- */
- struct GNUNET_TIME_Absolute timestamp;
-
- /* struct GNUNET_CADET_Data with payload */
-};
-
-
-/**
- * Info about the traffic state for a client in a channel.
- */
-struct CadetChannelReliability
-{
- /**
- * Channel this is about.
- */
- struct CadetChannel *ch;
-
- /**
- * DLL of messages sent and not yet ACK'd.
- */
- struct CadetReliableMessage *head_sent;
- struct CadetReliableMessage *tail_sent;
-
- /**
- * DLL of messages received out of order.
- */
- struct CadetReliableMessage *head_recv;
- struct CadetReliableMessage *tail_recv;
-
- /**
- * Messages received.
- */
- unsigned int n_recv;
-
- /**
- * Next MID to use for outgoing traffic.
- */
- uint32_t mid_send;
-
- /**
- * Next MID expected for incoming traffic.
- */
- uint32_t mid_recv;
-
- /**
- * Handle for queued unique data CREATE, DATA_ACK.
- */
- struct CadetChannelQueue *uniq;
-
- /**
- * Can we send data to the client?
- */
- int client_ready;
-
- /**
- * Can the client send data to us?
- */
- int client_allowed;
-
- /**
- * Task to resend/poll in case no ACK is received.
- */
- GNUNET_SCHEDULER_TaskIdentifier retry_task;
-
- /**
- * Counter for exponential backoff.
- */
- struct GNUNET_TIME_Relative retry_timer;
-
- /**
- * How long does it usually take to get an ACK.
- */
- struct GNUNET_TIME_Relative expected_delay;
-};
-
-
-/**
- * Struct containing all information regarding a channel to a remote client.
- */
-struct CadetChannel
-{
- /**
- * Tunnel this channel is in.
- */
- struct CadetTunnel3 *t;
-
- /**
- * Destination port of the channel.
- */
- uint32_t port;
-
- /**
- * Global channel number ( < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
- */
- CADET_ChannelNumber gid;
-
- /**
- * Local tunnel number for root (owner) client.
- * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI or 0 )
- */
- CADET_ChannelNumber lid_root;
-
- /**
- * Local tunnel number for local destination clients (incoming number)
- * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV or 0).
- */
- CADET_ChannelNumber lid_dest;
-
- /**
- * Channel state.
- */
- enum CadetChannelState state;
-
- /**
- * Is the tunnel bufferless (minimum latency)?
- */
- int nobuffer;
-
- /**
- * Is the tunnel reliable?
- */
- int reliable;
-
- /**
- * Last time the channel was used
- */
- struct GNUNET_TIME_Absolute timestamp;
-
- /**
- * Client owner of the tunnel, if any
- */
- struct CadetClient *root;
-
- /**
- * Client destination of the tunnel, if any.
- */
- struct CadetClient *dest;
-
- /**
- * Flag to signal the destruction of the channel.
- * If this is set GNUNET_YES the channel will be destroyed
- * when the queue is empty.
- */
- int destroy;
-
- /**
- * Total (reliable) messages pending ACK for this channel.
- */
- unsigned int pending_messages;
-
- /**
- * Reliability data.
- * Only present (non-NULL) at the owner of a tunnel.
- */
- struct CadetChannelReliability *root_rel;
-
- /**
- * Reliability data.
- * Only present (non-NULL) at the destination of a tunnel.
- */
- struct CadetChannelReliability *dest_rel;
-
-};
-
-
-/******************************************************************************/
-/******************************* GLOBALS
***********************************/
-/******************************************************************************/
-
-/**
- * Global handle to the statistics service.
- */
-extern struct GNUNET_STATISTICS_Handle *stats;
-
-/**
- * Local peer own ID (memory efficient handle).
- */
-extern GNUNET_PEER_Id myid;
-
-
-/******************************************************************************/
-/******************************** STATIC
***********************************/
-/******************************************************************************/
-
-/**
- * Destroy a reliable message after it has been acknowledged, either by
- * direct mid ACK or bitfield. Updates the appropriate data structures and
- * timers and frees all memory.
- *
- * @param copy Message that is no longer needed: remote peer got it.
- * @param update_time Is the timing information relevant?
- * If this message is ACK in a batch the timing information
- * is skewed by the retransmission, count only for the
- * retransmitted message.
- */
-static int
-rel_message_free (struct CadetReliableMessage *copy, int update_time);
-
-/**
- * send a channel create message.
- *
- * @param ch Channel for which to send.
- */
-static void
-send_create (struct CadetChannel *ch);
-
-/**
- * Confirm we got a channel create, FWD ack.
- *
- * @param ch The channel to confirm.
- * @param fwd Should we send a FWD ACK? (going dest->root)
- * @param reaction This ACK is a reaction to a duplicate CREATE, don't save.
- */
-static void
-send_ack (struct CadetChannel *ch, int fwd, int reaction);
-
-
-
-/**
- * Test if the channel is loopback: both root and dest are on the local peer.
- *
- * @param ch Channel to test.
- *
- * @return #GNUNET_YES if channel is loopback, #GNUNET_NO otherwise.
- */
-static int
-is_loopback (const struct CadetChannel *ch)
-{
- if (NULL != ch->t)
- return GMT_is_loopback (ch->t);
-
- return (NULL != ch->root && NULL != ch->dest);
-}
-
-
-/**
- * Save a copy of the data message for later retransmission.
- *
- * @param msg Message to copy.
- * @param mid Message ID.
- * @param rel Reliability data for retransmission.
- */
-static struct CadetReliableMessage *
-copy_message (const struct GNUNET_CADET_Data *msg, uint32_t mid,
- struct CadetChannelReliability *rel)
-{
- struct CadetReliableMessage *copy;
- uint16_t size;
-
- size = ntohs (msg->header.size);
- copy = GNUNET_malloc (sizeof (*copy) + size);
- copy->mid = mid;
- copy->rel = rel;
- copy->type = GNUNET_MESSAGE_TYPE_CADET_DATA;
- memcpy (©[1], msg, size);
-
- return copy;
-}
-
-/**
- * We have received a message out of order, or the client is not ready.
- * Buffer it until we receive an ACK from the client or the missing
- * message from the channel.
- *
- * @param msg Message to buffer (MUST be of type CADET_DATA).
- * @param rel Reliability data to the corresponding direction.
- */
-static void
-add_buffered_data (const struct GNUNET_CADET_Data *msg,
- struct CadetChannelReliability *rel)
-{
- struct CadetReliableMessage *copy;
- struct CadetReliableMessage *prev;
- uint32_t mid;
-
- mid = ntohl (msg->mid);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data %u\n", mid);
-
- rel->n_recv++;
-
- // FIXME do something better than O(n), although n < 64...
- // FIXME start from the end (most messages are the latest ones)
- for (prev = rel->head_recv; NULL != prev; prev = prev->next)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " prev %u\n", prev->mid);
- if (prev->mid == mid)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " already there!\n");
- return;
- }
- else if (GM_is_pid_bigger (prev->mid, mid))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " bingo!\n");
- copy = copy_message (msg, mid, rel);
- GNUNET_CONTAINER_DLL_insert_before (rel->head_recv, rel->tail_recv,
- prev, copy);
- return;
- }
- }
- copy = copy_message (msg, mid, rel);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " insert at tail!\n");
- GNUNET_CONTAINER_DLL_insert_tail (rel->head_recv, rel->tail_recv, copy);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data END\n");
-}
-
-
-/**
- * Add a destination client to a channel, initializing all data structures
- * in the channel and the client.
- *
- * @param ch Channel to which add the destination.
- * @param c Client which to add to the channel.
- */
-static void
-add_destination (struct CadetChannel *ch, struct CadetClient *c)
-{
- if (NULL != ch->dest)
- {
- GNUNET_break (0);
- return;
- }
-
- /* Assign local id as destination */
- ch->lid_dest = GML_get_next_chid (c);
-
- /* Store in client's hashmap */
- GML_channel_add (c, ch->lid_dest, ch);
-
- GNUNET_break (NULL == ch->dest_rel);
- ch->dest_rel = GNUNET_new (struct CadetChannelReliability);
- ch->dest_rel->ch = ch;
- ch->dest_rel->expected_delay.rel_value_us = 0;
- ch->dest_rel->retry_timer = CADET_RETRANSMIT_TIME;
-
- ch->dest = c;
-}
-
-
-/**
- * Set options in a channel, extracted from a bit flag field.
- *
- * @param ch Channel to set options to.
- * @param options Bit array in host byte order.
- */
-static void
-channel_set_options (struct CadetChannel *ch, uint32_t options)
-{
- ch->nobuffer = (options & GNUNET_CADET_OPTION_NOBUFFER) != 0 ?
- GNUNET_YES : GNUNET_NO;
- ch->reliable = (options & GNUNET_CADET_OPTION_RELIABLE) != 0 ?
- GNUNET_YES : GNUNET_NO;
-}
-
-
-/**
- * Get a bit flag field with the options of a channel.
- *
- * @param ch Channel to get options from.
- *
- * @return Bit array in host byte order.
- */
-static uint32_t
-channel_get_options (struct CadetChannel *ch)
-{
- uint32_t options;
-
- options = 0;
- if (ch->nobuffer)
- options |= GNUNET_CADET_OPTION_NOBUFFER;
- if (ch->reliable)
- options |= GNUNET_CADET_OPTION_RELIABLE;
-
- return options;
-}
-
-
-/**
- * Notify a client that the channel is no longer valid.
- *
- * @param ch Channel that is destroyed.
- * @param local_only Should we avoid sending it to other peers?
- */
-static void
-send_destroy (struct CadetChannel *ch, int local_only)
-{
- struct GNUNET_CADET_ChannelManage msg;
-
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
- msg.header.size = htons (sizeof (msg));
- msg.chid = htonl (ch->gid);
-
- /* If root is not NULL, notify.
- * If it's NULL, check lid_root. When a local destroy comes in, root
- * is set to NULL but lid_root is left untouched. In this case, do nothing,
- * the client is the one who requested the channel to be destroyed.
- */
- if (NULL != ch->root)
- GML_send_channel_destroy (ch->root, ch->lid_root);
- else if (0 == ch->lid_root && GNUNET_NO == local_only)
- GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO, NULL);
-
- if (NULL != ch->dest)
- GML_send_channel_destroy (ch->dest, ch->lid_dest);
- else if (0 == ch->lid_dest && GNUNET_NO == local_only)
- GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_YES, NULL);
-}
-
-
-/**
- * Notify the destination client that a new incoming channel was created.
- *
- * @param ch Channel that was created.
- */
-static void
-send_client_create (struct CadetChannel *ch)
-{
- uint32_t opt;
-
- if (NULL == ch->dest)
- return;
-
- opt = 0;
- opt |= GNUNET_YES == ch->reliable ? GNUNET_CADET_OPTION_RELIABLE : 0;
- opt |= GNUNET_YES == ch->nobuffer ? GNUNET_CADET_OPTION_NOBUFFER : 0;
- GML_send_channel_create (ch->dest, ch->lid_dest, ch->port, opt,
- GMT_get_destination (ch->t));
-
-}
-
-
-/**
- * Send data to a client.
- *
- * If the client is ready, send directly, otherwise buffer while listening
- * for a local ACK.
- *
- * @param ch Channel
- * @param msg Message.
- * @param fwd Is this a fwd (root->dest) message?
- */
-static void
-send_client_data (struct CadetChannel *ch,
- const struct GNUNET_CADET_Data *msg,
- int fwd)
-{
- if (fwd)
- {
- if (ch->dest_rel->client_ready)
- GML_send_data (ch->dest, msg, ch->lid_dest);
- else
- add_buffered_data (msg, ch->dest_rel);
- }
- else
- {
- if (ch->root_rel->client_ready)
- GML_send_data (ch->root, msg, ch->lid_root);
- else
- add_buffered_data (msg, ch->root_rel);
- }
-}
-
-
-/**
- * Send a buffered message to the client, for in order delivery or
- * as result of client ACK.
- *
- * @param ch Channel on which to empty the message buffer.
- * @param c Client to send to.
- * @param fwd Is this to send FWD data?.
- */
-static void
-send_client_buffered_data (struct CadetChannel *ch,
- struct CadetClient *c,
- int fwd)
-{
- struct CadetReliableMessage *copy;
- struct CadetChannelReliability *rel;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data\n");
- rel = fwd ? ch->dest_rel : ch->root_rel;
- if (GNUNET_NO == rel->client_ready)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "client not ready\n");
- return;
- }
-
- copy = rel->head_recv;
- /* We never buffer channel management messages */
- if (NULL != copy)
- {
- if (copy->mid == rel->mid_recv || GNUNET_NO == ch->reliable)
- {
- struct GNUNET_CADET_Data *msg = (struct GNUNET_CADET_Data *) ©[1];
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " have %u! now expecting %u\n",
- copy->mid, rel->mid_recv + 1);
- send_client_data (ch, msg, fwd);
- rel->n_recv--;
- rel->mid_recv++;
- GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE RECV %p\n", copy);
- GNUNET_free (copy);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " reliable && don't have %u, next is %u\n",
- rel->mid_recv,
- copy->mid);
- if (GNUNET_YES == ch->destroy)
- {
- /* We don't have the next data piece and the remote peer has closed the
- * channel. We won't receive it anymore, so just destroy the channel.
- * FIXME: wait some time to allow other connections to
- * deliver missing messages
- */
- send_destroy (ch, GNUNET_YES);
- GMCH_destroy (ch);
- }
- }
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data END\n");
-}
-
-
-/**
- * Allow a client to send more data.
- *
- * In case the client was already allowed to send data, do nothing.
- *
- * @param ch Channel.
- * @param fwd Is this a FWD ACK? (FWD ACKs are sent to root)
- */
-static void
-send_client_ack (struct CadetChannel *ch, int fwd)
-{
- struct CadetChannelReliability *rel = fwd ? ch->root_rel : ch->dest_rel;
- struct CadetClient *c = fwd ? ch->root : ch->dest;
-
- if (NULL == c)
- {
- GNUNET_break (GNUNET_NO != ch->destroy);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " sending %s ack to client on channel %s\n",
- GM_f2s (fwd), GMCH_2s (ch));
-
- if (NULL == rel)
- {
- GNUNET_break (0);
- return;
- }
-
- if (GNUNET_YES == rel->client_allowed)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " already allowed\n");
- return;
- }
- rel->client_allowed = GNUNET_YES;
-
- GML_send_ack (c, fwd ? ch->lid_root : ch->lid_dest);
-}
-
-
-/**
- * Notify the root that the destination rejected the channel.
- *
- * @param ch Rejected channel.
- */
-static void
-send_client_nack (struct CadetChannel *ch)
-{
- if (NULL == ch->root)
- {
- GNUNET_break (0);
- return;
- }
- GML_send_channel_nack (ch->root, ch->lid_root);
-}
-
-
-/**
- * We haven't received an ACK after a certain time: restransmit the message.
- *
- * @param cls Closure (CadetChannelReliability with the message to restransmit)
- * @param tc TaskContext.
- */
-static void
-channel_retransmit_message (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct CadetChannelReliability *rel = cls;
- struct CadetReliableMessage *copy;
- struct CadetChannel *ch;
- struct GNUNET_CADET_Data *payload;
- int fwd;
-
- rel->retry_task = GNUNET_SCHEDULER_NO_TASK;
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- return;
-
- ch = rel->ch;
- copy = rel->head_sent;
- if (NULL == copy)
- {
- GNUNET_break (0);
- return;
- }
-
- payload = (struct GNUNET_CADET_Data *) ©[1];
- fwd = (rel == ch->root_rel);
-
- /* Message not found in the queue that we are going to use. */
- LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! RETRANSMIT %u\n", copy->mid);
-
- GMCH_send_prebuilt_message (&payload->header, ch, fwd, copy);
- GNUNET_STATISTICS_update (stats, "# data retransmitted", 1, GNUNET_NO);
-}
-
-
-/**
- * We haven't received an Channel ACK after a certain time: resend the CREATE.
- *
- * @param cls Closure (CadetChannelReliability of the channel to recreate)
- * @param tc TaskContext.
- */
-static void
-channel_recreate (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct CadetChannelReliability *rel = cls;
-
- rel->retry_task = GNUNET_SCHEDULER_NO_TASK;
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- return;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! RE-CREATE\n");
- GNUNET_STATISTICS_update (stats, "# data retransmitted", 1, GNUNET_NO);
-
- if (rel == rel->ch->root_rel)
- {
- send_create (rel->ch);
- }
- else if (rel == rel->ch->dest_rel)
- {
- send_ack (rel->ch, GNUNET_YES, GNUNET_NO);
- }
- else
- {
- GNUNET_break (0);
- }
-
-}
-
-
-/**
- * Message has been sent: start retransmission timer.
- *
- * @param cls Closure (queue structure).
- * @param t Tunnel.
- * @param q Queue handler (no longer valid).
- * @param type Type of message.
- * @param size Size of the message.
- */
-static void
-ch_message_sent (void *cls,
- struct CadetTunnel3 *t,
- struct CadetTunnel3Queue *q,
- uint16_t type, size_t size)
-{
- struct CadetChannelQueue *chq = cls;
- struct CadetReliableMessage *copy = chq->copy;
- struct CadetChannelReliability *rel;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "channel message sent callback %s\n",
- GM_m2s (chq->type));
-
- switch (chq->type)
- {
- case GNUNET_MESSAGE_TYPE_CADET_DATA:
- LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SENT DATA MID %u\n", copy->mid);
- GNUNET_assert (chq == copy->chq);
- copy->timestamp = GNUNET_TIME_absolute_get ();
- rel = copy->rel;
- if (GNUNET_SCHEDULER_NO_TASK == rel->retry_task)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "!! scheduling retry in 4 * %s\n",
- GNUNET_STRINGS_relative_time_to_string (rel->expected_delay,
- GNUNET_YES));
- if (0 != rel->expected_delay.rel_value_us)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "!! delay != 0\n");
- rel->retry_timer =
- GNUNET_TIME_relative_multiply (rel->expected_delay,
- CADET_RETRANSMIT_MARGIN);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "!! delay reset\n");
- rel->retry_timer = CADET_RETRANSMIT_TIME;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "!! using delay %s\n",
- GNUNET_STRINGS_relative_time_to_string (rel->retry_timer,
- GNUNET_NO));
- rel->retry_task =
- GNUNET_SCHEDULER_add_delayed (rel->retry_timer,
- &channel_retransmit_message, rel);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "!! retry task %u\n", rel->retry_task);
- }
- copy->chq = NULL;
- break;
-
-
- case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK:
- LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SENT %s\n", GM_m2s (chq->type));
- rel = chq->rel;
- GNUNET_assert (rel->uniq == chq);
- rel->uniq = NULL;
-
- if (CADET_CHANNEL_READY != rel->ch->state
- && GNUNET_MESSAGE_TYPE_CADET_DATA_ACK != type
- && GNUNET_NO == rel->ch->destroy)
- {
- GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == rel->retry_task);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! STD BACKOFF %s\n",
- GNUNET_STRINGS_relative_time_to_string (rel->retry_timer,
- GNUNET_NO));
- rel->retry_timer = GNUNET_TIME_STD_BACKOFF (rel->retry_timer);
- rel->retry_task = GNUNET_SCHEDULER_add_delayed (rel->retry_timer,
- &channel_recreate,
rel);
- }
- break;
-
- default:
- GNUNET_break (0);
- }
-
- GNUNET_free (chq);
-}
-
-
-/**
- * send a channel create message.
- *
- * @param ch Channel for which to send.
- */
-static void
-send_create (struct CadetChannel *ch)
-{
- struct GNUNET_CADET_ChannelCreate msgcc;
-
- msgcc.header.size = htons (sizeof (msgcc));
- msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE);
- msgcc.chid = htonl (ch->gid);
- msgcc.port = htonl (ch->port);
- msgcc.opt = htonl (channel_get_options (ch));
-
- GMCH_send_prebuilt_message (&msgcc.header, ch, GNUNET_YES, NULL);
-}
-
-
-/**
- * Confirm we got a channel create or FWD ack.
- *
- * @param ch The channel to confirm.
- * @param fwd Should we send a FWD ACK? (going dest->root)
- * @param reaction This ACK is a reaction to a duplicate CREATE, don't save.
- */
-static void
-send_ack (struct CadetChannel *ch, int fwd, int reaction)
-{
- struct GNUNET_CADET_ChannelManage msg;
-
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " sending channel %s ack for channel %s\n",
- GM_f2s (fwd), GMCH_2s (ch));
-
- msg.chid = htonl (ch->gid);
- GMCH_send_prebuilt_message (&msg.header, ch, !fwd, reaction ? &msg : NULL);
-}
-
-
-/**
- * Send a message and don't keep any info about it: we won't need to cancel it
- * or resend it.
- *
- * @param msg Header of the message to fire away.
- * @param ch Channel on which the message should go.
- * @param force Is this a forced (undroppable) message?
- */
-static void
-fire_and_forget (const struct GNUNET_MessageHeader *msg,
- struct CadetChannel *ch,
- int force)
-{
- GNUNET_break (NULL == GMT_send_prebuilt_message (msg, ch->t, NULL,
- force, NULL, NULL));
-}
-
-
-/**
- * Notify that a channel create didn't succeed.
- *
- * @param ch The channel to reject.
- */
-static void
-send_nack (struct CadetChannel *ch)
-{
- struct GNUNET_CADET_ChannelManage msg;
-
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " sending channel NACK for channel %s\n",
- GMCH_2s (ch));
-
- msg.chid = htonl (ch->gid);
- GMCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO, NULL);
-}
-
-
-/**
- * Destroy all reliable messages queued for a channel,
- * during a channel destruction.
- * Frees the reliability structure itself.
- *
- * @param rel Reliability data for a channel.
- */
-static void
-channel_rel_free_all (struct CadetChannelReliability *rel)
-{
- struct CadetReliableMessage *copy;
- struct CadetReliableMessage *next;
-
- if (NULL == rel)
- return;
-
- for (copy = rel->head_recv; NULL != copy; copy = next)
- {
- next = copy->next;
- GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE BATCH RECV %p\n", copy);
- GNUNET_break (NULL == copy->chq);
- GNUNET_free (copy);
- }
- for (copy = rel->head_sent; NULL != copy; copy = next)
- {
- next = copy->next;
- GNUNET_CONTAINER_DLL_remove (rel->head_sent, rel->tail_sent, copy);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE BATCH %p\n", copy);
- if (NULL != copy->chq)
- {
- if (NULL != copy->chq->tq)
- {
- GMT_cancel (copy->chq->tq);
- /* ch_message_sent will free copy->q */
- }
- else
- {
- GNUNET_free (copy->chq);
- GNUNET_break (0);
- }
- }
- GNUNET_free (copy);
- }
- if (NULL != rel->uniq && NULL != rel->uniq->tq)
- {
- GMT_cancel (rel->uniq->tq);
- /* ch_message_sent is called freeing uniq */
- }
- if (GNUNET_SCHEDULER_NO_TASK != rel->retry_task)
- {
- GNUNET_SCHEDULER_cancel (rel->retry_task);
- rel->retry_task = GNUNET_SCHEDULER_NO_TASK;
- }
- GNUNET_free (rel);
-}
-
-
-/**
- * Mark future messages as ACK'd.
- *
- * @param rel Reliability data.
- * @param msg DataACK message with a bitfield of future ACK'd messages.
- */
-static void
-channel_rel_free_sent (struct CadetChannelReliability *rel,
- const struct GNUNET_CADET_DataACK *msg)
-{
- struct CadetReliableMessage *copy;
- struct CadetReliableMessage *next;
- uint64_t bitfield;
- uint64_t mask;
- uint32_t mid;
- uint32_t target;
- unsigned int i;
-
- bitfield = msg->futures;
- mid = ntohl (msg->mid);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "!!! free_sent_reliable %u %llX\n",
- mid, bitfield);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " rel %p, head %p\n",
- rel, rel->head_sent);
- for (i = 0, copy = rel->head_sent;
- i < 64 && NULL != copy && 0 != bitfield;
- i++)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " trying bit %u (mid %u)\n",
- i, mid + i + 1);
- mask = 0x1LL << i;
- if (0 == (bitfield & mask))
- continue;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " set!\n");
- /* Bit was set, clear the bit from the bitfield */
- bitfield &= ~mask;
-
- /* The i-th bit was set. Do we have that copy? */
- /* Skip copies with mid < target */
- target = mid + i + 1;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " target %u\n", target);
- while (NULL != copy && GM_is_pid_bigger (target, copy->mid))
- copy = copy->next;
-
- /* Did we run out of copies? (previously freed, it's ok) */
- if (NULL == copy)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "run out of copies...\n");
- return;
- }
-
- /* Did we overshoot the target? (previously freed, it's ok) */
- if (GM_is_pid_bigger (copy->mid, target))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " next copy %u\n", copy->mid);
- continue;
- }
-
- /* Now copy->mid == target, free it */
- next = copy->next;
- GNUNET_break (GNUNET_YES != rel_message_free (copy, GNUNET_YES));
- copy = next;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "free_sent_reliable END\n");
-}
-
-
-/**
- * Destroy a reliable message after it has been acknowledged, either by
- * direct mid ACK or bitfield. Updates the appropriate data structures and
- * timers and frees all memory.
- *
- * @param copy Message that is no longer needed: remote peer got it.
- * @param update_time Is the timing information relevant?
- * If this message is ACK in a batch the timing information
- * is skewed by the retransmission, count only for the
- * retransmitted message.
- *
- * @return #GNUNET_YES if channel was destroyed as a result of the call,
- * #GNUNET_NO otherwise.
- */
-static int
-rel_message_free (struct CadetReliableMessage *copy, int update_time)
-{
- struct CadetChannelReliability *rel;
- struct GNUNET_TIME_Relative time;
-
- rel = copy->rel;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Freeing %u\n", copy->mid);
- if (update_time)
- {
- time = GNUNET_TIME_absolute_get_duration (copy->timestamp);
- if (0 == rel->expected_delay.rel_value_us)
- rel->expected_delay = time;
- else
- {
- rel->expected_delay.rel_value_us *= 7;
- rel->expected_delay.rel_value_us += time.rel_value_us;
- rel->expected_delay.rel_value_us /= 8;
- }
- LOG (GNUNET_ERROR_TYPE_INFO, "!!! took %s, new delay %s\n",
- GNUNET_STRINGS_relative_time_to_string (time, GNUNET_NO),
- GNUNET_STRINGS_relative_time_to_string (rel->expected_delay,
- GNUNET_NO));
- rel->retry_timer = rel->expected_delay;
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_INFO, "!!! batch free, ignoring timing\n");
- }
- rel->ch->pending_messages--;
- if (NULL != copy->chq)
- {
- GMT_cancel (copy->chq->tq);
- /* copy->q is set to NULL by ch_message_sent */
- }
- GNUNET_CONTAINER_DLL_remove (rel->head_sent, rel->tail_sent, copy);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE %p\n", copy);
- GNUNET_free (copy);
-
- if (GNUNET_NO != rel->ch->destroy && 0 == rel->ch->pending_messages)
- {
- GMCH_destroy (rel->ch);
- return GNUNET_YES;
- }
- return GNUNET_NO;
-}
-
-
-/**
- * Channel was ACK'd by remote peer, mark as ready and cancel retransmission.
- *
- * @param ch Channel to mark as ready.
- * @param fwd Was the ACK message a FWD ACK? (dest->root, SYNACK)
- */
-static void
-channel_confirm (struct CadetChannel *ch, int fwd)
-{
- struct CadetChannelReliability *rel;
- enum CadetChannelState oldstate;
-
- rel = fwd ? ch->root_rel : ch->dest_rel;
- if (NULL == rel)
- {
- GNUNET_break (GNUNET_NO != ch->destroy);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " channel confirm %s %s\n",
- GM_f2s (fwd), GMCH_2s (ch));
- oldstate = ch->state;
- ch->state = CADET_CHANNEL_READY;
-
- if (CADET_CHANNEL_READY != oldstate || GNUNET_YES == is_loopback (ch))
- {
- rel->client_ready = GNUNET_YES;
- rel->expected_delay = rel->retry_timer;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " !! retry timer confirm %s\n",
- GNUNET_STRINGS_relative_time_to_string (rel->retry_timer, GNUNET_NO));
- if (GMT_get_connections_buffer (ch->t) > 0 || GMT_is_loopback (ch->t))
- send_client_ack (ch, fwd);
-
- if (GNUNET_SCHEDULER_NO_TASK != rel->retry_task)
- {
- GNUNET_SCHEDULER_cancel (rel->retry_task);
- rel->retry_task = GNUNET_SCHEDULER_NO_TASK;
- }
- else if (NULL != rel->uniq)
- {
- GMT_cancel (rel->uniq->tq);
- /* ch_message_sent will free and NULL uniq */
- }
- else
- {
- if (GNUNET_NO == is_loopback (ch))
- {
- /* We SHOULD have been trying to retransmit this! */
- GNUNET_break (0);
- }
- }
- }
-
- /* In case of a FWD ACK (SYNACK) send a BCK ACK (ACK). */
- if (GNUNET_YES == fwd)
- send_ack (ch, GNUNET_NO, GNUNET_NO);
-}
-
-
-/**
- * Save a copy to retransmit in case it gets lost.
- *
- * Initializes all needed callbacks and timers.
- *
- * @param ch Channel this message goes on.
- * @param msg Message to copy.
- * @param fwd Is this fwd traffic?
- */
-static struct CadetReliableMessage *
-channel_save_copy (struct CadetChannel *ch,
- const struct GNUNET_MessageHeader *msg,
- int fwd)
-{
- struct CadetChannelReliability *rel;
- struct CadetReliableMessage *copy;
- uint32_t mid;
- uint16_t type;
- uint16_t size;
-
- rel = fwd ? ch->root_rel : ch->dest_rel;
- mid = rel->mid_send - 1;
- type = ntohs (msg->type);
- size = ntohs (msg->size);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SAVE %u %s\n", mid, GM_m2s (type));
- copy = GNUNET_malloc (sizeof (struct CadetReliableMessage) + size);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " at %p\n", copy);
- copy->mid = mid;
- copy->rel = rel;
- copy->type = type;
- memcpy (©[1], msg, size);
- GNUNET_CONTAINER_DLL_insert_tail (rel->head_sent, rel->tail_sent, copy);
- ch->pending_messages++;
-
- return copy;
-}
-
-
-/**
- * Create a new channel.
- *
- * @param t Tunnel this channel is in.
- * @param owner Client that owns the channel, NULL for foreign channels.
- * @param lid_root Local ID for root client.
- *
- * @return A new initialized channel. NULL on error.
- */
-static struct CadetChannel *
-channel_new (struct CadetTunnel3 *t,
- struct CadetClient *owner,
- CADET_ChannelNumber lid_root)
-{
- struct CadetChannel *ch;
-
- ch = GNUNET_new (struct CadetChannel);
- ch->root = owner;
- ch->lid_root = lid_root;
- ch->t = t;
-
- GNUNET_STATISTICS_update (stats, "# channels", 1, GNUNET_NO);
-
- if (NULL != owner)
- {
- ch->gid = GMT_get_next_chid (t);
- GML_channel_add (owner, lid_root, ch);
- }
- GMT_add_channel (t, ch);
-
- return ch;
-}
-
-
-/**
- * Handle a loopback message: call the appropriate handler for the message
type.
- *
- * @param ch Channel this message is on.
- * @param msgh Message header.
- * @param fwd Is this FWD traffic?
- */
-void
-handle_loopback (struct CadetChannel *ch,
- const struct GNUNET_MessageHeader *msgh,
- int fwd)
-{
- uint16_t type;
-
- type = ntohs (msgh->type);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Loopback %s %s message!\n",
- GM_f2s (fwd), GM_m2s (type));
-
- switch (type)
- {
- case GNUNET_MESSAGE_TYPE_CADET_DATA:
- /* Don't send hop ACK, wait for client to ACK */
- LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! SEND loopback %u (%u)\n",
- ntohl (((struct GNUNET_CADET_Data *) msgh)->mid), ntohs
(msgh->size));
- GMCH_handle_data (ch, (struct GNUNET_CADET_Data *) msgh, fwd);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK:
- GMCH_handle_data_ack (ch, (struct GNUNET_CADET_DataACK *) msgh, fwd);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE:
- GMCH_handle_create (ch->t,
- (struct GNUNET_CADET_ChannelCreate *) msgh);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK:
- GMCH_handle_ack (ch,
- (struct GNUNET_CADET_ChannelManage *) msgh,
- fwd);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK:
- GMCH_handle_nack (ch);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
- GMCH_handle_destroy (ch,
- (struct GNUNET_CADET_ChannelManage *) msgh,
- fwd);
- break;
-
- default:
- GNUNET_break_op (0);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "end-to-end message not known (%u)\n",
- ntohs (msgh->type));
- }
-}
-
-
-
-/******************************************************************************/
-/******************************** API
***********************************/
-/******************************************************************************/
-
-/**
- * Destroy a channel and free all resources.
- *
- * @param ch Channel to destroy.
- */
-void
-GMCH_destroy (struct CadetChannel *ch)
-{
- struct CadetClient *c;
- struct CadetTunnel3 *t;
-
- if (NULL == ch)
- return;
- if (2 == ch->destroy)
- return; /* recursive call */
- ch->destroy = 2;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying channel %s:%u\n",
- GMT_2s (ch->t), ch->gid);
- GMCH_debug (ch);
-
- c = ch->root;
- if (NULL != c)
- {
- GML_channel_remove (c, ch->lid_root, ch);
- }
-
- c = ch->dest;
- if (NULL != c)
- {
- GML_channel_remove (c, ch->lid_dest, ch);
- }
-
- channel_rel_free_all (ch->root_rel);
- channel_rel_free_all (ch->dest_rel);
-
- t = ch->t;
- GMT_remove_channel (t, ch);
- GNUNET_STATISTICS_update (stats, "# channels", -1, GNUNET_NO);
-
- GNUNET_free (ch);
- GMT_destroy_if_empty (t);
-}
-
-
-/**
- * Get the channel's public ID.
- *
- * @param ch Channel.
- *
- * @return ID used to identify the channel with the remote peer.
- */
-CADET_ChannelNumber
-GMCH_get_id (const struct CadetChannel *ch)
-{
- return ch->gid;
-}
-
-
-/**
- * Get the channel tunnel.
- *
- * @param ch Channel to get the tunnel from.
- *
- * @return tunnel of the channel.
- */
-struct CadetTunnel3 *
-GMCH_get_tunnel (const struct CadetChannel *ch)
-{
- return ch->t;
-}
-
-
-/**
- * Get free buffer space towards the client on a specific channel.
- *
- * @param ch Channel.
- * @param fwd Is query about FWD traffic?
- *
- * @return Free buffer space [0 - 64]
- */
-unsigned int
-GMCH_get_buffer (struct CadetChannel *ch, int fwd)
-{
- struct CadetChannelReliability *rel;
-
- rel = fwd ? ch->dest_rel : ch->root_rel;
-
- /* If rel is NULL it means that the end is not yet created,
- * most probably is a loopback channel at the point of sending
- * the ChannelCreate to itself.
- */
- if (NULL == rel)
- return 64;
-
- return (64 - rel->n_recv);
-}
-
-
-/**
- * Get flow control status of end point: is client allow to send?
- *
- * @param ch Channel.
- * @param fwd Is query about FWD traffic? (Request root status).
- *
- * @return #GNUNET_YES if client is allowed to send us data.
- */
-int
-GMCH_get_allowed (struct CadetChannel *ch, int fwd)
-{
- struct CadetChannelReliability *rel;
-
- rel = fwd ? ch->root_rel : ch->dest_rel;
-
- if (NULL == rel)
- {
- /* Probably shutting down: root/dest NULL'ed to mark disconnection */
- GNUNET_break (GNUNET_NO != ch->destroy);
- return 0;
- }
-
- return rel->client_allowed;
-}
-
-
-/**
- * Is the root client for this channel on this peer?
- *
- * @param ch Channel.
- * @param fwd Is this for fwd traffic?
- *
- * @return #GNUNET_YES in case it is.
- */
-int
-GMCH_is_origin (struct CadetChannel *ch, int fwd)
-{
- struct CadetClient *c;
-
- c = fwd ? ch->root : ch->dest;
- return NULL != c;
-}
-
-
-/**
- * Is the destination client for this channel on this peer?
- *
- * @param ch Channel.
- * @param fwd Is this for fwd traffic?
- *
- * @return #GNUNET_YES in case it is.
- */
-int
-GMCH_is_terminal (struct CadetChannel *ch, int fwd)
-{
- struct CadetClient *c;
-
- c = fwd ? ch->dest : ch->root;
- return NULL != c;
-}
-
-
-/**
- * Send an end-to-end ACK message for the most recent in-sequence payload.
- *
- * If channel is not reliable, do nothing.
- *
- * @param ch Channel this is about.
- * @param fwd Is for FWD traffic? (ACK dest->owner)
- */
-void
-GMCH_send_data_ack (struct CadetChannel *ch, int fwd)
-{
- struct GNUNET_CADET_DataACK msg;
- struct CadetChannelReliability *rel;
- struct CadetReliableMessage *copy;
- unsigned int delta;
- uint64_t mask;
- uint32_t ack;
-
- if (GNUNET_NO == ch->reliable)
- {
- return;
- }
- rel = fwd ? ch->dest_rel : ch->root_rel;
- ack = rel->mid_recv - 1;
- LOG (GNUNET_ERROR_TYPE_INFO, "===> DATA_ACK for %u\n", ack);
-
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_DATA_ACK);
- msg.header.size = htons (sizeof (msg));
- msg.chid = htonl (ch->gid);
- msg.futures = 0;
- for (copy = rel->head_recv; NULL != copy; copy = copy->next)
- {
- if (copy->type != GNUNET_MESSAGE_TYPE_CADET_DATA)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "!! Type %s, expected DATA\n",
- GM_m2s (copy->type));
- continue;
- }
- if (copy->mid == ack + 1)
- {
- ack++;
- continue;
- }
- delta = copy->mid - (ack + 1);
- if (63 < delta)
- break;
- mask = 0x1LL << delta;
- msg.futures |= mask;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " !! setting bit for %u (delta %u) (%llX) -> %llX\n",
- copy->mid, delta, mask, msg.futures);
- }
- msg.mid = htonl (ack);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "!!! ACK for %u, futures %llX\n",
- ack, msg.futures);
-
- GMCH_send_prebuilt_message (&msg.header, ch, !fwd, NULL);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "send_data_ack END\n");
-}
-
-
-/**
- * Allow a client to send us more data, in case it was choked.
- *
- * @param ch Channel.
- * @param fwd Is this about FWD traffic? (Root client).
- */
-void
-GMCH_allow_client (struct CadetChannel *ch, int fwd)
-{
- struct CadetChannelReliability *rel;
- unsigned int buffer;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GMCH allow\n");
-
- if (CADET_CHANNEL_READY != ch->state)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " channel not ready yet!\n");
- return;
- }
-
- if (GNUNET_YES == ch->reliable)
- {
- rel = fwd ? ch->root_rel : ch->dest_rel;
- if (NULL == rel)
- {
- GNUNET_break (GNUNET_NO != ch->destroy);
- return;
- }
- if (NULL != rel->head_sent)
- {
- if (64 <= rel->mid_send - rel->head_sent->mid)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " too big MID gap! Wait for ACK.\n");
- return;
- }
- else
- LOG (GNUNET_ERROR_TYPE_DEBUG, " gap ok: %u - %u\n",
- rel->head_sent->mid, rel->mid_send);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " head sent is NULL\n");
- }
- }
-
- if (is_loopback (ch))
- buffer = GMCH_get_buffer (ch, fwd);
- else
- buffer = GMT_get_connections_buffer (ch->t);
-
- if (0 == buffer)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " no buffer space.\n");
- return;
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space %u, allowing\n", buffer);
- send_client_ack (ch, fwd);
-}
-
-
-/**
- * Log channel info.
- *
- * @param ch Channel.
- */
-void
-GMCH_debug (struct CadetChannel *ch)
-{
- if (NULL == ch)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "*** DEBUG NULL CHANNEL ***\n");
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %s:%X (%p)\n",
- GMT_2s (ch->t), ch->gid, ch);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " root %p/%p\n",
- ch->root, ch->root_rel);
- if (NULL != ch->root)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " cli %s\n", GML_2s (ch->root));
- LOG (GNUNET_ERROR_TYPE_DEBUG, " ready %s\n",
- ch->root_rel->client_ready ? "YES" : "NO");
- LOG (GNUNET_ERROR_TYPE_DEBUG, " id %X\n", ch->lid_root);
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " dest %p/%p\n",
- ch->dest, ch->dest_rel);
- if (NULL != ch->dest)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " cli %s\n", GML_2s (ch->dest));
- LOG (GNUNET_ERROR_TYPE_DEBUG, " ready %s\n",
- ch->dest_rel->client_ready ? "YES" : "NO");
- LOG (GNUNET_ERROR_TYPE_DEBUG, " id %X\n", ch->lid_dest);
- }
-}
-
-
-/**
- * Handle an ACK given by a client.
- *
- * Mark client as ready and send him any buffered data we could have for him.
- *
- * @param ch Channel.
- * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by dest and go BCK)
- */
-void
-GMCH_handle_local_ack (struct CadetChannel *ch, int fwd)
-{
- struct CadetChannelReliability *rel;
- struct CadetClient *c;
-
- rel = fwd ? ch->dest_rel : ch->root_rel;
- c = fwd ? ch->dest : ch->root;
-
- rel->client_ready = GNUNET_YES;
- send_client_buffered_data (ch, c, fwd);
-
- if (GNUNET_YES == ch->destroy && 0 == rel->n_recv)
- {
- send_destroy (ch, GNUNET_YES);
- GMCH_destroy (ch);
- }
- /* if loopback is marked for destruction, no need to ACK to the other peer,
- * it requested the destruction and is already gone, therefore, else if.
- */
- else if (is_loopback (ch))
- {
- unsigned int buffer;
-
- buffer = GMCH_get_buffer (ch, fwd);
- if (0 < buffer)
- GMCH_allow_client (ch, fwd);
-
- return;
- }
- GMT_send_connection_acks (ch->t);
-}
-
-
-/**
- * Handle data given by a client.
- *
- * Check whether the client is allowed to send in this tunnel, save if channel
- * is reliable and send an ACK to the client if there is still buffer space
- * in the tunnel.
- *
- * @param ch Channel.
- * @param c Client which sent the data.
- * @param message Message.
- * @param fwd Is this a FWD data?
- *
- * @return GNUNET_OK if everything goes well, GNUNET_SYSERR in case of en
error.
- */
-int
-GMCH_handle_local_data (struct CadetChannel *ch,
- struct CadetClient *c,
- struct GNUNET_MessageHeader *message,
- int fwd)
-{
- struct CadetChannelReliability *rel;
- struct GNUNET_CADET_Data *payload;
- size_t size = ntohs (message->size);
- uint16_t p2p_size = sizeof(struct GNUNET_CADET_Data) + size;
- unsigned char cbuf[p2p_size];
-
- /* Is the client in the channel? */
- if ( !( (fwd &&
- ch->root == c)
- ||
- (!fwd &&
- ch->dest == c) ) )
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- rel = fwd ? ch->root_rel : ch->dest_rel;
-
- if (GNUNET_NO == rel->client_allowed)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
-
- rel->client_allowed = GNUNET_NO;
-
- /* Ok, everything is correct, send the message. */
- payload = (struct GNUNET_CADET_Data *) cbuf;
- payload->mid = htonl (rel->mid_send);
- rel->mid_send++;
- memcpy (&payload[1], message, size);
- payload->header.size = htons (p2p_size);
- payload->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_DATA);
- payload->chid = htonl (ch->gid);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channel...\n");
- GMCH_send_prebuilt_message (&payload->header, ch, fwd, NULL);
-
- if (is_loopback (ch))
- {
- if (GMCH_get_buffer (ch, fwd) > 0)
- GMCH_allow_client (ch, fwd);
-
- return GNUNET_OK;
- }
-
- if (GMT_get_connections_buffer (ch->t) > 0)
- {
- GMCH_allow_client (ch, fwd);
- }
-
- return GNUNET_OK;
-}
-
-
-/**
- * Handle a channel destroy requested by a client.
- *
- * Destroy the channel and the tunnel in case this was the last channel.
- *
- * @param ch Channel.
- * @param c Client that requested the destruction (to avoid notifying him).
- * @param is_root Is the request coming from root?
- */
-void
-GMCH_handle_local_destroy (struct CadetChannel *ch,
- struct CadetClient *c,
- int is_root)
-{
- ch->destroy = GNUNET_YES;
- /* Cleanup after the tunnel */
- if (GNUNET_NO == is_root && c == ch->dest)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is destination.\n", GML_2s (c));
- GML_client_delete_channel (c, ch, ch->lid_dest);
- ch->dest = NULL;
- }
- if (GNUNET_YES == is_root && c == ch->root)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Client %s is owner.\n", GML_2s (c));
- GML_client_delete_channel (c, ch, ch->lid_root);
- ch->root = NULL;
- }
-
- send_destroy (ch, GNUNET_NO);
- if (0 == ch->pending_messages)
- GMCH_destroy (ch);
-}
-
-
-/**
- * Handle a channel create requested by a client.
- *
- * Create the channel and the tunnel in case this was the first0 channel.
- *
- * @param c Client that requested the creation (will be the root).
- * @param msg Create Channel message.
- *
- * @return GNUNET_OK if everything went fine, GNUNET_SYSERR otherwise.
- */
-int
-GMCH_handle_local_create (struct CadetClient *c,
- struct GNUNET_CADET_ChannelMessage *msg)
-{
- struct CadetChannel *ch;
- struct CadetTunnel3 *t;
- struct CadetPeer *peer;
- CADET_ChannelNumber chid;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " towards %s:%u\n",
- GNUNET_i2s (&msg->peer), ntohl (msg->port));
- chid = ntohl (msg->channel_id);
-
- /* Sanity check for duplicate channel IDs */
- if (NULL != GML_channel_get (c, chid))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
-
- peer = GMP_get (&msg->peer);
- GMP_add_tunnel (peer);
- t = GMP_get_tunnel (peer);
-
- if (GMP_get_short_id (peer) == myid)
- {
- GMT_change_cstate (t, CADET_TUNNEL3_READY);
- }
- else
- {
- /* FIXME change to a tunnel API, eliminate ch <-> peer connection */
- GMP_connect (peer);
- }
-
- /* Create channel */
- ch = channel_new (t, c, chid);
- if (NULL == ch)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- ch->port = ntohl (msg->port);
- channel_set_options (ch, ntohl (msg->opt));
-
- /* In unreliable channels, we'll use the DLL to buffer BCK data */
- ch->root_rel = GNUNET_new (struct CadetChannelReliability);
- ch->root_rel->ch = ch;
- ch->root_rel->retry_timer = CADET_RETRANSMIT_TIME;
- ch->root_rel->expected_delay.rel_value_us = 0;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "CREATED CHANNEL %s\n", GMCH_2s (ch));
-
- send_create (ch);
-
- return GNUNET_OK;
-}
-
-
-/**
- * Handler for cadet network payload traffic.
- *
- * @param ch Channel for the message.
- * @param msg Unencryted data message.
- * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
- * #GNUNET_YES if message is FWD on the respective channel
(loopback)
- * #GNUNET_NO if message is BCK on the respective channel (loopback)
- * #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-void
-GMCH_handle_data (struct CadetChannel *ch,
- const struct GNUNET_CADET_Data *msg,
- int fwd)
-{
- struct CadetChannelReliability *rel;
- struct CadetClient *c;
- uint32_t mid;
-
- /* If this is a remote (non-loopback) channel, find 'fwd'. */
- if (GNUNET_SYSERR == fwd)
- {
- if (is_loopback (ch))
- {
- /* It is a loopback channel after all... */
- GNUNET_break (0);
- return;
- }
- fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO;
- }
-
- /* Initialize FWD/BCK data */
- c = fwd ? ch->dest : ch->root;
- rel = fwd ? ch->dest_rel : ch->root_rel;
-
- if (NULL == c)
- {
- GNUNET_break (GNUNET_NO != ch->destroy);
- return;
- }
-
- if (CADET_CHANNEL_READY != ch->state)
- {
- if (GNUNET_NO == fwd)
- {
- /* If we are the root, this means the other peer has sent traffic before
- * receiving our ACK. Even if the SYNACK goes missing, no traffic should
- * be sent before the ACK.
- */
- GNUNET_break_op (0);
- return;
- }
- /* If we are the dest, this means that the SYNACK got to the root but
- * the ACK went missing. Treat this as an ACK.
- */
- channel_confirm (ch, GNUNET_NO);
- }
-
- GNUNET_STATISTICS_update (stats, "# data received", 1, GNUNET_NO);
-
- mid = ntohl (msg->mid);
- LOG (GNUNET_ERROR_TYPE_INFO, "<=== DATA %u %s on channel %s\n",
- mid, GM_f2s (fwd), GMCH_2s (ch));
-
- if (GNUNET_NO == ch->reliable ||
- ( !GM_is_pid_bigger (rel->mid_recv, mid) &&
- GM_is_pid_bigger (rel->mid_recv + 64, mid) ) )
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "RECV %u (%u)\n",
- mid, ntohs (msg->header.size));
- if (GNUNET_YES == ch->reliable)
- {
- /* Is this the exact next expected messasge? */
- if (mid == rel->mid_recv)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "as expected\n");
- rel->mid_recv++;
- send_client_data (ch, msg, fwd);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "save for later\n");
- add_buffered_data (msg, rel);
- }
- }
- else
- {
- /* Tunnel is unreliable: send to clients directly */
- /* FIXME: accept Out Of Order traffic */
- rel->mid_recv = mid + 1;
- send_client_data (ch, msg, fwd);
- }
- }
- else
- {
- GNUNET_break_op (GM_is_pid_bigger (rel->mid_recv, mid));
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "MID %u not expected (%u - %u), dropping!\n",
- mid, rel->mid_recv, rel->mid_recv + 63);
- }
-
- GMCH_send_data_ack (ch, fwd);
-}
-
-
-/**
- * Handler for cadet network traffic end-to-end ACKs.
- *
- * @param ch Channel on which we got this message.
- * @param msg Data message.
- * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
- * #GNUNET_YES if message is FWD on the respective channel
(loopback)
- * #GNUNET_NO if message is BCK on the respective channel (loopback)
- * #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-void
-GMCH_handle_data_ack (struct CadetChannel *ch,
- const struct GNUNET_CADET_DataACK *msg,
- int fwd)
-{
- struct CadetChannelReliability *rel;
- struct CadetReliableMessage *copy;
- struct CadetReliableMessage *next;
- uint32_t ack;
- int work;
-
- /* If this is a remote (non-loopback) channel, find 'fwd'. */
- if (GNUNET_SYSERR == fwd)
- {
- if (is_loopback (ch))
- {
- /* It is a loopback channel after all... */
- GNUNET_break (0);
- return;
- }
- /* Inverted: if message came 'FWD' is a 'BCK ACK'. */
- fwd = (NULL != ch->dest) ? GNUNET_NO : GNUNET_YES;
- }
-
- ack = ntohl (msg->mid);
- LOG (GNUNET_ERROR_TYPE_INFO, "<=== %s ACK %u\n", GM_f2s (fwd), ack);
-
- if (GNUNET_YES == fwd)
- {
- rel = ch->root_rel;
- }
- else
- {
- rel = ch->dest_rel;
- }
- if (NULL == rel)
- {
- GNUNET_break_op (GNUNET_NO != ch->destroy);
- return;
- }
-
- /* Free ACK'd copies: no need to retransmit those anymore FIXME refactor */
- for (work = GNUNET_NO, copy = rel->head_sent; copy != NULL; copy = next)
- {
- if (GM_is_pid_bigger (copy->mid, ack))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " head %u, out!\n", copy->mid);
- channel_rel_free_sent (rel, msg);
- break;
- }
- work = GNUNET_YES;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " id %u\n", copy->mid);
- next = copy->next;
- if (GNUNET_YES == rel_message_free (copy, GNUNET_YES))
- return;
- }
-
- /* ACK client if needed and possible */
- GMCH_allow_client (ch, fwd);
-
- /* If some message was free'd, update the retransmission delay */
- if (GNUNET_YES == work)
- {
- if (GNUNET_SCHEDULER_NO_TASK != rel->retry_task)
- {
- GNUNET_SCHEDULER_cancel (rel->retry_task);
- rel->retry_task = GNUNET_SCHEDULER_NO_TASK;
- if (NULL != rel->head_sent && NULL == rel->head_sent->chq)
- {
- struct GNUNET_TIME_Absolute new_target;
- struct GNUNET_TIME_Relative delay;
-
- delay = GNUNET_TIME_relative_multiply (rel->retry_timer,
- CADET_RETRANSMIT_MARGIN);
- new_target = GNUNET_TIME_absolute_add (rel->head_sent->timestamp,
- delay);
- delay = GNUNET_TIME_absolute_get_remaining (new_target);
- rel->retry_task =
- GNUNET_SCHEDULER_add_delayed (delay,
- &channel_retransmit_message,
- rel);
- }
- }
- else
- {
- /* Work was done but no task was pending? Shouldn't happen! */
- GNUNET_break (0);
- }
- }
-}
-
-
-/**
- * Handler for channel create messages.
- *
- * Does not have fwd parameter because it's always 'FWD': channel is incoming.
- *
- * @param t Tunnel this channel will be in.
- * @param msg Channel crate message.
- */
-struct CadetChannel *
-GMCH_handle_create (struct CadetTunnel3 *t,
- const struct GNUNET_CADET_ChannelCreate *msg)
-{
- CADET_ChannelNumber chid;
- struct CadetChannel *ch;
- struct CadetClient *c;
- int new_channel;
- int reaction;
-
- reaction = GNUNET_NO;
- chid = ntohl (msg->chid);
- ch = GMT_get_channel (t, chid);
- if (NULL == ch)
- {
- /* Create channel */
- ch = channel_new (t, NULL, 0);
- ch->gid = chid;
- channel_set_options (ch, ntohl (msg->opt));
- new_channel = GNUNET_YES;
- }
- else
- {
- new_channel = GNUNET_NO;
- }
-
- if (GNUNET_YES == new_channel || GMT_is_loopback (t))
- {
- /* Find a destination client */
- ch->port = ntohl (msg->port);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " port %u\n", ch->port);
- c = GML_client_get_by_port (ch->port);
- if (NULL == c)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " no client has port registered\n");
- if (is_loopback (ch))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " loopback: destroy on handler\n");
- send_nack (ch);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " not loopback: destroy now\n");
- send_nack (ch);
- GMCH_destroy (ch);
- }
- return NULL;
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " client %p has port registered\n", c);
- }
-
- add_destination (ch, c);
- if (GNUNET_YES == ch->reliable)
- LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Reliable\n");
- else
- LOG (GNUNET_ERROR_TYPE_DEBUG, "!!! Not Reliable\n");
-
- send_client_create (ch);
- ch->state = CADET_CHANNEL_SENT;
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate create channel\n");
- reaction = GNUNET_YES;
- if (GNUNET_SCHEDULER_NO_TASK != ch->dest_rel->retry_task)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " clearing retry task\n");
- /* we were waiting to re-send our 'SYNACK', wait no more! */
- GNUNET_SCHEDULER_cancel (ch->dest_rel->retry_task);
- ch->dest_rel->retry_task = GNUNET_SCHEDULER_NO_TASK;
- }
- }
- send_ack (ch, GNUNET_YES, reaction);
-
- return ch;
-}
-
-
-/**
- * Handler for channel NACK messages.
- *
- * NACK messages always go dest -> root, no need for 'fwd' or 'msg' parameter.
- *
- * @param ch Channel.
- */
-void
-GMCH_handle_nack (struct CadetChannel *ch)
-{
- send_client_nack (ch);
- GMCH_destroy (ch);
-}
-
-
-/**
- * Handler for channel ack messages.
- *
- * @param ch Channel.
- * @param msg Message.
- * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
- * #GNUNET_YES if message is FWD on the respective channel
(loopback)
- * #GNUNET_NO if message is BCK on the respective channel (loopback)
- * #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-void
-GMCH_handle_ack (struct CadetChannel *ch,
- const struct GNUNET_CADET_ChannelManage *msg,
- int fwd)
-{
- /* If this is a remote (non-loopback) channel, find 'fwd'. */
- if (GNUNET_SYSERR == fwd)
- {
- if (is_loopback (ch))
- {
- /* It is a loopback channel after all... */
- GNUNET_break (0);
- return;
- }
- fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO;
- }
-
- channel_confirm (ch, !fwd);
-}
-
-
-/**
- * Handler for channel destroy messages.
- *
- * @param ch Channel to be destroyed of.
- * @param msg Message.
- * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
- * #GNUNET_YES if message is FWD on the respective channel
(loopback)
- * #GNUNET_NO if message is BCK on the respective channel (loopback)
- * #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-void
-GMCH_handle_destroy (struct CadetChannel *ch,
- const struct GNUNET_CADET_ChannelManage *msg,
- int fwd)
-{
- struct CadetChannelReliability *rel;
-
- /* If this is a remote (non-loopback) channel, find 'fwd'. */
- if (GNUNET_SYSERR == fwd)
- {
- if (is_loopback (ch))
- {
- /* It is a loopback channel after all... */
- GNUNET_break (0);
- return;
- }
- fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO;
- }
-
- GMCH_debug (ch);
- if ( (fwd && NULL == ch->dest) || (!fwd && NULL == ch->root) )
- {
- /* Not for us (don't destroy twice a half-open loopback channel) */
- return;
- }
-
- rel = fwd ? ch->dest_rel : ch->root_rel;
- if (0 == rel->n_recv)
- {
- send_destroy (ch, GNUNET_YES);
- GMCH_destroy (ch);
- }
- else
- {
- ch->destroy = GNUNET_YES;
- }
-}
-
-
-/**
- * Sends an already built message on a channel.
- *
- * If the channel is on a loopback tunnel, notifies the appropriate destination
- * client locally.
- *
- * On a normal channel passes the message to the tunnel for encryption and
- * sending on a connection.
- *
- * This function DOES NOT save the message for retransmission.
- *
- * @param message Message to send. Function makes a copy of it.
- * @param ch Channel on which this message is transmitted.
- * @param fwd Is this a fwd message?
- * @param existing_copy This is a retransmission, don't save a copy.
- */
-void
-GMCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
- struct CadetChannel *ch, int fwd,
- void *existing_copy)
-{
- struct CadetChannelQueue *chq;
- uint16_t type;
-
- type = ntohs (message->type);
- LOG (GNUNET_ERROR_TYPE_INFO, "===> %s %s on channel %s\n",
- GM_m2s (type), GM_f2s (fwd), GMCH_2s (ch));
-
- if (GMT_is_loopback (ch->t))
- {
- handle_loopback (ch, message, fwd);
- return;
- }
-
- switch (type)
- {
- struct GNUNET_CADET_Data *payload;
- case GNUNET_MESSAGE_TYPE_CADET_DATA:
-
- payload = (struct GNUNET_CADET_Data *) message;
- LOG (GNUNET_ERROR_TYPE_INFO, "===> %s %u\n",
- GM_m2s (type), ntohl (payload->mid));
- if (GNUNET_YES == ch->reliable)
- {
- chq = GNUNET_new (struct CadetChannelQueue);
- chq->type = type;
- if (NULL == existing_copy)
- chq->copy = channel_save_copy (ch, message, fwd);
- else
- {
- chq->copy = (struct CadetReliableMessage *) existing_copy;
- if (NULL != chq->copy->chq)
- {
- /* Last retransmission was queued but not yet sent!
- * This retransmission was scheduled by a ch_message_sent which
- * followed a very fast RTT, so the tiny delay made the
- * retransmission function to execute before the previous
- * retransmitted message even had a chance to leave the peer.
- * Cancel this message and wait until the pending
- * retransmission leaves the peer and ch_message_sent starts
- * the timer for the next one.
- */
- GNUNET_free (chq);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " exisitng copy not yet transmitted!\n");
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " using existing copy: %p {r:%p q:%p t:%u}\n",
- existing_copy,
- chq->copy->rel, chq->copy->chq, chq->copy->type);
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " new chq: %p\n", chq);
- chq->copy->chq = chq;
- chq->tq = GMT_send_prebuilt_message (message, ch->t, NULL,
- NULL != existing_copy,
- &ch_message_sent, chq);
- /* q itself is stored in copy */
- GNUNET_assert (NULL != chq->tq || GNUNET_NO != ch->destroy);
- }
- else
- {
- fire_and_forget (message, ch, GNUNET_NO);
- }
- break;
-
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK:
- if (GNUNET_YES == fwd || NULL != existing_copy)
- {
- /* BCK ACK (going FWD) is just a response for a SYNACK, don't keep*/
- fire_and_forget (message, ch, GNUNET_YES);
- return;
- }
- /* fall-trough */
- case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE:
- chq = GNUNET_new (struct CadetChannelQueue);
- chq->type = type;
- chq->rel = fwd ? ch->root_rel : ch->dest_rel;
- if (NULL != chq->rel->uniq)
- {
- if (NULL != chq->rel->uniq->tq)
- {
- GMT_cancel (chq->rel->uniq->tq);
- /* ch_message_sent is called, freeing and NULLing uniq */
- }
- else
- {
- GNUNET_break (0);
- GNUNET_free (chq->rel->uniq);
- }
- }
- chq->tq = GMT_send_prebuilt_message (message, ch->t, NULL, GNUNET_YES,
- &ch_message_sent, chq);
- if (NULL == chq->tq)
- {
- GNUNET_break (0);
- GNUNET_free (chq);
- chq = NULL;
- return;
- }
- chq->rel->uniq = chq;
- break;
-
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK:
- fire_and_forget (message, ch, GNUNET_YES);
- break;
-
-
- default:
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "type %s unknown!\n", GM_m2s (type));
- fire_and_forget (message, ch, GNUNET_YES);
- }
-}
-
-
-/**
- * Get the static string for identification of the channel.
- *
- * @param ch Channel.
- *
- * @return Static string with the channel IDs.
- */
-const char *
-GMCH_2s (const struct CadetChannel *ch)
-{
- static char buf[64];
-
- if (NULL == ch)
- return "(NULL Channel)";
-
- sprintf (buf, "%s:%u gid:%X (%X / %X)",
- GMT_2s (ch->t), ch->port, ch->gid, ch->lid_root, ch->lid_dest);
-
- return buf;
-}
Deleted: gnunet/src/mesh/gnunet-service-cadet_channel.h
===================================================================
--- gnunet/src/mesh/gnunet-service-cadet_channel.h 2014-05-07 12:07:02 UTC
(rev 33185)
+++ gnunet/src/mesh/gnunet-service-cadet_channel.h 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -1,349 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2013 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_channel.h
- * @brief cadet service; dealing with end-to-end channels
- * @author Bartlomiej Polot
- *
- * All functions in this file should use the prefix GMCH (Gnunet Cadet CHannel)
- */
-
-#ifndef GNUNET_SERVICE_CADET_CHANNEL_H
-#define GNUNET_SERVICE_CADET_CHANNEL_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0 /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#include "cadet_protocol.h"
-#include "cadet.h"
-
-/**
- * Struct containing all information regarding a channel to a remote client.
- */
-struct CadetChannel;
-
-
-#include "gnunet-service-cadet_tunnel.h"
-#include "gnunet-service-cadet_local.h"
-
-
-/**
- * Destroy a channel and free all resources.
- *
- * @param ch Channel to destroy.
- */
-void
-GMCH_destroy (struct CadetChannel *ch);
-
-
-/**
- * Get the channel's public ID.
- *
- * @param ch Channel.
- *
- * @return ID used to identify the channel with the remote peer.
- */
-CADET_ChannelNumber
-GMCH_get_id (const struct CadetChannel *ch);
-
-/**
- * Get the channel tunnel.
- *
- * @param ch Channel to get the tunnel from.
- *
- * @return tunnel of the channel.
- */
-struct CadetTunnel3 *
-GMCH_get_tunnel (const struct CadetChannel *ch);
-
-/**
- * Get free buffer space towards the client on a specific channel.
- *
- * @param ch Channel.
- * @param fwd Is query about FWD traffic?
- *
- * @return Free buffer space [0 - 64]
- */
-unsigned int
-GMCH_get_buffer (struct CadetChannel *ch, int fwd);
-
-
-/**
- * Get flow control status of end point: is client allow to send?
- *
- * @param ch Channel.
- * @param fwd Is query about FWD traffic? (Request root status).
- *
- * @return #GNUNET_YES if client is allowed to send us data.
- */
-int
-GMCH_get_allowed (struct CadetChannel *ch, int fwd);
-
-
-/**
- * Is the root client for this channel on this peer?
- *
- * @param ch Channel.
- * @param fwd Is this for fwd traffic?
- *
- * @return #GNUNET_YES in case it is.
- */
-int
-GMCH_is_origin (struct CadetChannel *ch, int fwd);
-
-/**
- * Is the destination client for this channel on this peer?
- *
- * @param ch Channel.
- * @param fwd Is this for fwd traffic?
- *
- * @return #GNUNET_YES in case it is.
- */
-int
-GMCH_is_terminal (struct CadetChannel *ch, int fwd);
-
-/**
- * Send an end-to-end ACK message for the most recent in-sequence payload.
- *
- * If channel is not reliable, do nothing.
- *
- * @param ch Channel this is about.
- * @param fwd Is for FWD traffic? (ACK dest->owner)
- */
-void
-GMCH_send_data_ack (struct CadetChannel *ch, int fwd);
-
-/**
- * Notify the destination client that a new incoming channel was created.
- *
- * @param ch Channel that was created.
- */
-void
-GMCH_send_create (struct CadetChannel *ch);
-
-/**
- * Allow a client to send us more data, in case it was choked.
- *
- * @param ch Channel.
- * @param fwd Is this about FWD traffic? (Root client).
- */
-void
-GMCH_allow_client (struct CadetChannel *ch, int fwd);
-
-/**
- * Log channel info.
- *
- * @param ch Channel.
- */
-void
-GMCH_debug (struct CadetChannel *ch);
-
-/**
- * Handle an ACK given by a client.
- *
- * Mark client as ready and send him any buffered data we could have for him.
- *
- * @param ch Channel.
- * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by root and go BCK)
- */
-void
-GMCH_handle_local_ack (struct CadetChannel *ch, int fwd);
-
-/**
- * Handle data given by a client.
- *
- * Check whether the client is allowed to send in this tunnel, save if channel
- * is reliable and send an ACK to the client if there is still buffer space
- * in the tunnel.
- *
- * @param ch Channel.
- * @param c Client which sent the data.
- * @param message Message.
- * @param fwd Is this a FWD data?
- *
- * @return GNUNET_OK if everything goes well, GNUNET_SYSERR in case of en
error.
- */
-int
-GMCH_handle_local_data (struct CadetChannel *ch,
- struct CadetClient *c,
- struct GNUNET_MessageHeader *message,
- int fwd);
-
-/**
- * Handle a channel destroy requested by a client.
- *
- * Destroy the channel and the tunnel in case this was the last channel.
- *
- * @param ch Channel.
- * @param c Client that requested the destruction (to avoid notifying him).
- * @param is_root Is the request coming from root?
- */
-void
-GMCH_handle_local_destroy (struct CadetChannel *ch,
- struct CadetClient *c,
- int is_root);
-
-/**
- * Handle a channel create requested by a client.
- *
- * Create the channel and the tunnel in case this was the first0 channel.
- *
- * @param c Client that requested the creation (will be the root).
- * @param msg Create Channel message.
- *
- * @return GNUNET_OK if everything went fine, GNUNET_SYSERR otherwise.
- */
-int
-GMCH_handle_local_create (struct CadetClient *c,
- struct GNUNET_CADET_ChannelMessage *msg);
-
-/**
- * Handler for cadet network payload traffic.
- *
- * @param ch Channel for the message.
- * @param msg Unencryted data message.
- * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
- * #GNUNET_YES if message is FWD on the respective channel
(loopback)
- * #GNUNET_NO if message is BCK on the respective channel (loopback)
- * #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-void
-GMCH_handle_data (struct CadetChannel *ch,
- const struct GNUNET_CADET_Data *msg,
- int fwd);
-
-/**
- * Handler for cadet network traffic end-to-end ACKs.
- *
- * @param ch Channel on which we got this message.
- * @param msg Data message.
- * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
- * #GNUNET_YES if message is FWD on the respective channel
(loopback)
- * #GNUNET_NO if message is BCK on the respective channel (loopback)
- * #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-void
-GMCH_handle_data_ack (struct CadetChannel *ch,
- const struct GNUNET_CADET_DataACK *msg,
- int fwd);
-
-/**
- * Handler for channel create messages.
- *
- * Does not have fwd parameter because it's always 'FWD': channel is incoming.
- *
- * @param t Tunnel this channel will be in.
- * @param msg Channel crate message.
- */
-struct CadetChannel *
-GMCH_handle_create (struct CadetTunnel3 *t,
- const struct GNUNET_CADET_ChannelCreate *msg);
-
-/**
- * Handler for channel NACK messages.
- *
- * NACK messages always go dest -> root, no need for 'fwd' or 'msg' parameter.
- *
- * @param ch Channel.
- */
-void
-GMCH_handle_nack (struct CadetChannel *ch);
-
-/**
- * Handler for channel ack messages.
- *
- * @param ch Channel this channel is to be created in.
- * @param msg Message.
- * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
- * #GNUNET_YES if message is FWD on the respective channel
(loopback)
- * #GNUNET_NO if message is BCK on the respective channel (loopback)
- * #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-void
-GMCH_handle_ack (struct CadetChannel *ch,
- const struct GNUNET_CADET_ChannelManage *msg,
- int fwd);
-
-/**
- * Handler for channel destroy messages.
- *
- * @param ch Channel this channel is to be destroyed of.
- * @param msg Message.
- * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
- * #GNUNET_YES if message is FWD on the respective channel
(loopback)
- * #GNUNET_NO if message is BCK on the respective channel (loopback)
- * #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-void
-GMCH_handle_destroy (struct CadetChannel *ch,
- const struct GNUNET_CADET_ChannelManage *msg,
- int fwd);
-
-/**
- * Sends an already built message on a channel.
- *
- * If the channel is on a loopback tunnel, notifies the appropriate destination
- * client locally.
- *
- * On a normal channel passes the message to the tunnel for encryption and
- * sending on a connection.
- *
- * This function DOES NOT save the message for retransmission.
- *
- * @param message Message to send. Function makes a copy of it.
- * @param ch Channel on which this message is transmitted.
- * @param fwd Is this a fwd message?
- * @param existing_copy This is a retransmission, don't save a copy.
- */
-void
-GMCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
- struct CadetChannel *ch, int fwd,
- void *existing_copy);
-
-/**
- * Get the static string for identification of the channel.
- *
- * @param ch Channel.i
- *
- * @return Static string with the channel IDs.
- */
-const char *
-GMCH_2s (const struct CadetChannel *ch);
-
-
-#if 0 /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_SERVICE_CADET_CHANNEL_H */
-#endif
-/* end of gnunet-service-cadet_channel.h */
Deleted: gnunet/src/mesh/gnunet-service-cadet_connection.c
===================================================================
--- gnunet/src/mesh/gnunet-service-cadet_connection.c 2014-05-07 12:07:02 UTC
(rev 33185)
+++ gnunet/src/mesh/gnunet-service-cadet_connection.c 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -1,3176 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2001-2013 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_connection.c
- * @brief GNUnet CADET service connection handling
- * @author Bartlomiej Polot
- */
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#include "gnunet_statistics_service.h"
-
-#include "cadet_path.h"
-#include "cadet_protocol.h"
-#include "cadet.h"
-#include "gnunet-service-cadet_connection.h"
-#include "gnunet-service-cadet_peer.h"
-#include "gnunet-service-cadet_tunnel.h"
-
-
-#define LOG(level, ...) GNUNET_log_from (level,"cadet-con",__VA_ARGS__)
-
-#define CADET_MAX_POLL_TIME GNUNET_TIME_relative_multiply (\
- GNUNET_TIME_UNIT_MINUTES,\
- 10)
-#define AVG_MSGS 32
-
-
-/******************************************************************************/
-/******************************** STRUCTS
**********************************/
-/******************************************************************************/
-
-/**
- * Struct to encapsulate all the Flow Control information to a peer to which
- * we are directly connected (on a core level).
- */
-struct CadetFlowControl
-{
- /**
- * Connection this controls.
- */
- struct CadetConnection *c;
-
- /**
- * How many messages are in the queue on this connection.
- */
- unsigned int queue_n;
-
- /**
- * How many messages do we accept in the queue.
- */
- unsigned int queue_max;
-
- /**
- * ID of the last packet sent towards the peer.
- */
- uint32_t last_pid_sent;
-
- /**
- * ID of the last packet received from the peer.
- */
- uint32_t last_pid_recv;
-
- /**
- * Last ACK sent to the peer (peer can't send more than this PID).
- */
- uint32_t last_ack_sent;
-
- /**
- * Last ACK sent towards the origin (for traffic towards leaf node).
- */
- uint32_t last_ack_recv;
-
- /**
- * Task to poll the peer in case of a lost ACK causes stall.
- */
- GNUNET_SCHEDULER_TaskIdentifier poll_task;
-
- /**
- * How frequently to poll for ACKs.
- */
- struct GNUNET_TIME_Relative poll_time;
-
- /**
- * Queued poll message, to cancel if not necessary anymore (got ACK).
- */
- struct CadetConnectionQueue *poll_msg;
-
- /**
- * Queued poll message, to cancel if not necessary anymore (got ACK).
- */
- struct CadetConnectionQueue *ack_msg;
-};
-
-/**
- * Keep a record of the last messages sent on this connection.
- */
-struct CadetConnectionPerformance
-{
- /**
- * Circular buffer for storing measurements.
- */
- double usecsperbyte[AVG_MSGS];
-
- /**
- * Running average of @c usecsperbyte.
- */
- double avg;
-
- /**
- * How many values of @c usecsperbyte are valid.
- */
- uint16_t size;
-
- /**
- * Index of the next "free" position in @c usecsperbyte.
- */
- uint16_t idx;
-};
-
-
-/**
- * Struct containing all information regarding a connection to a peer.
- */
-struct CadetConnection
-{
- /**
- * Tunnel this connection is part of.
- */
- struct CadetTunnel3 *t;
-
- /**
- * Flow control information for traffic fwd.
- */
- struct CadetFlowControl fwd_fc;
-
- /**
- * Flow control information for traffic bck.
- */
- struct CadetFlowControl bck_fc;
-
- /**
- * Measure connection performance on the endpoint.
- */
- struct CadetConnectionPerformance *perf;
-
- /**
- * ID of the connection.
- */
- struct GNUNET_CADET_Hash id;
-
- /**
- * State of the connection.
- */
- enum CadetConnectionState state;
-
- /**
- * Path being used for the tunnel. At the origin of the connection
- * it's a pointer to the destination's path pool, otherwise just a copy.
- */
- struct CadetPeerPath *path;
-
- /**
- * Position of the local peer in the path.
- */
- unsigned int own_pos;
-
- /**
- * Task to keep the used paths alive at the owner,
- * time tunnel out on all the other peers.
- */
- GNUNET_SCHEDULER_TaskIdentifier fwd_maintenance_task;
-
- /**
- * Task to keep the used paths alive at the destination,
- * time tunnel out on all the other peers.
- */
- GNUNET_SCHEDULER_TaskIdentifier bck_maintenance_task;
-
- /**
- * Queue handle for maintainance traffic. One handle for FWD and BCK since
- * one peer never needs to maintain both directions (no loopback
connections).
- */
- struct CadetPeerQueue *maintenance_q;
-
- /**
- * Counter to do exponential backoff when creating a connection (max 64).
- */
- unsigned short create_retry;
-
- /**
- * Pending message count.
- */
- int pending_messages;
-
- /**
- * Destroy flag: if true, destroy on last message.
- */
- int destroy;
-};
-
-/**
- * Handle for messages queued but not yet sent.
- */
-struct CadetConnectionQueue
-{
- /**
- * Peer queue handle, to cancel if necessary.
- */
- struct CadetPeerQueue *q;
-
- /**
- * Was this a forced message? (Do not account for it)
- */
- int forced;
-
- /**
- * Continuation to call once sent.
- */
- GMC_sent cont;
-
- /**
- * Closure for @c cont.
- */
- void *cont_cls;
-};
-
-/******************************************************************************/
-/******************************* GLOBALS
***********************************/
-/******************************************************************************/
-
-/**
- * Global handle to the statistics service.
- */
-extern struct GNUNET_STATISTICS_Handle *stats;
-
-/**
- * Local peer own ID (memory efficient handle).
- */
-extern GNUNET_PEER_Id myid;
-
-/**
- * Local peer own ID (full value).
- */
-extern struct GNUNET_PeerIdentity my_full_id;
-
-/**
- * Connections known, indexed by cid (CadetConnection).
- */
-static struct GNUNET_CONTAINER_MultiHashMap *connections;
-
-/**
- * How many connections are we willing to maintain.
- * Local connections are always allowed, even if there are more connections
than max.
- */
-static unsigned long long max_connections;
-
-/**
- * How many messages *in total* are we willing to queue, divide by number of
- * connections to get connection queue size.
- */
-static unsigned long long max_msgs_queue;
-
-/**
- * How often to send path keepalives. Paths timeout after 4 missed.
- */
-static struct GNUNET_TIME_Relative refresh_connection_time;
-
-/**
- * How often to send path create / ACKs.
- */
-static struct GNUNET_TIME_Relative create_connection_time;
-
-
-/******************************************************************************/
-/******************************** STATIC
***********************************/
-/******************************************************************************/
-
-#if 0 // avoid compiler warning for unused static function
-static void
-fc_debug (struct CadetFlowControl *fc)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " IN: %u/%u\n",
- fc->last_pid_recv, fc->last_ack_sent);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " OUT: %u/%u\n",
- fc->last_pid_sent, fc->last_ack_recv);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " QUEUE: %u/%u\n",
- fc->queue_n, fc->queue_max);
-}
-
-static void
-connection_debug (struct CadetConnection *c)
-{
- if (NULL == c)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "*** DEBUG NULL CONNECTION ***\n");
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s:%X\n",
- peer2s (c->t->peer), GMC_2s (c));
- LOG (GNUNET_ERROR_TYPE_DEBUG, " state: %u, pending msgs: %u\n",
- c->state, c->pending_messages);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD FC\n");
- fc_debug (&c->fwd_fc);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK FC\n");
- fc_debug (&c->bck_fc);
-}
-#endif
-
-
-/**
- * Schedule next keepalive task, taking in consideration
- * the connection state and number of retries.
- *
- * @param c Connection for which to schedule the next keepalive.
- * @param fwd Direction for the next keepalive.
- */
-static void
-schedule_next_keepalive (struct CadetConnection *c, int fwd);
-
-
-/**
- * Resets the connection timeout task, some other message has done the
- * task's job.
- * - For the first peer on the direction this means to send
- * a keepalive or a path confirmation message (either create or ACK).
- * - For all other peers, this means to destroy the connection,
- * due to lack of activity.
- * Starts the timeout if no timeout was running (connection just created).
- *
- * @param c Connection whose timeout to reset.
- * @param fwd Is this forward?
- */
-static void
-connection_reset_timeout (struct CadetConnection *c, int fwd);
-
-
-/**
- * Get string description for tunnel state. Reentrant.
- *
- * @param s Tunnel state.
- *
- * @return String representation.
- */
-static const char *
-GMC_state2s (enum CadetConnectionState s)
-{
- switch (s)
- {
- case CADET_CONNECTION_NEW:
- return "CADET_CONNECTION_NEW";
- case CADET_CONNECTION_SENT:
- return "CADET_CONNECTION_SENT";
- case CADET_CONNECTION_ACK:
- return "CADET_CONNECTION_ACK";
- case CADET_CONNECTION_READY:
- return "CADET_CONNECTION_READY";
- case CADET_CONNECTION_DESTROYED:
- return "CADET_CONNECTION_DESTROYED";
- default:
- return "CADET_CONNECTION_STATE_ERROR";
- }
-}
-
-
-/**
- * Initialize a Flow Control structure to the initial state.
- *
- * @param fc Flow Control structure to initialize.
- */
-static void
-fc_init (struct CadetFlowControl *fc)
-{
- fc->last_pid_sent = (uint32_t) -1; /* Next (expected) = 0 */
- fc->last_pid_recv = (uint32_t) -1;
- fc->last_ack_sent = (uint32_t) 0;
- fc->last_ack_recv = (uint32_t) 0;
- fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
- fc->poll_time = GNUNET_TIME_UNIT_SECONDS;
- fc->queue_n = 0;
- fc->queue_max = (max_msgs_queue / max_connections) + 1;
-}
-
-
-/**
- * Find a connection.
- *
- * @param cid Connection ID.
- */
-static struct CadetConnection *
-connection_get (const struct GNUNET_CADET_Hash *cid)
-{
- return GNUNET_CONTAINER_multihashmap_get (connections, GM_h2hc (cid));
-}
-
-
-static void
-connection_change_state (struct CadetConnection* c,
- enum CadetConnectionState state)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Connection %s state %s -> %s\n",
- GMC_2s (c), GMC_state2s (c->state), GMC_state2s (state));
- if (CADET_CONNECTION_DESTROYED == c->state)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "state not changing anymore\n");
- return;
- }
- c->state = state;
- if (CADET_CONNECTION_READY == state)
- c->create_retry = 1;
-}
-
-
-/**
- * Callback called when a queued ACK message is sent.
- *
- * @param cls Closure (FC).
- * @param c Connection this message was on.
- * @param q Queue handler this call invalidates.
- * @param type Type of message sent.
- * @param fwd Was this a FWD going message?
- * @param size Size of the message.
- */
-static void
-ack_sent (void *cls,
- struct CadetConnection *c,
- struct CadetConnectionQueue *q,
- uint16_t type, int fwd, size_t size)
-{
- struct CadetFlowControl *fc = cls;
-
- fc->ack_msg = NULL;
-}
-
-
-/**
- * Send an ACK on the connection, informing the predecessor about
- * the available buffer space. Should not be called in case the peer
- * is origin (no predecessor) in the @c fwd direction.
- *
- * Note that for fwd ack, the FWD mean forward *traffic* (root->dest),
- * the ACK itself goes "back" (dest->root).
- *
- * @param c Connection on which to send the ACK.
- * @param buffer How much space free to advertise?
- * @param fwd Is this FWD ACK? (Going dest -> root)
- * @param force Don't optimize out.
- */
-static void
-send_ack (struct CadetConnection *c, unsigned int buffer, int fwd, int force)
-{
- struct CadetFlowControl *next_fc;
- struct CadetFlowControl *prev_fc;
- struct GNUNET_CADET_ACK msg;
- uint32_t ack;
- int delta;
-
- /* If origin, there is no connection to send ACKs. Wrong function! */
- if (GMC_is_origin (c, fwd))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "connection %s is origin in %s\n",
- GMC_2s (c), GM_f2s (fwd));
- GNUNET_break (0);
- return;
- }
-
- next_fc = fwd ? &c->fwd_fc : &c->bck_fc;
- prev_fc = fwd ? &c->bck_fc : &c->fwd_fc;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "connection send %s ack on %s\n",
- GM_f2s (fwd), GMC_2s (c));
-
- /* Check if we need to transmit the ACK. */
- delta = prev_fc->last_ack_sent - prev_fc->last_pid_recv;
- if (3 < delta && buffer < delta && GNUNET_NO == force)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending ACK, buffer > 3\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " last pid recv: %u, last ack sent: %u\n",
- prev_fc->last_pid_recv, prev_fc->last_ack_sent);
- return;
- }
-
- /* Ok, ACK might be necessary, what PID to ACK? */
- ack = prev_fc->last_pid_recv + buffer;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " ACK %u\n", ack);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " last pid %u, last ack %u, qmax %u, q %u\n",
- prev_fc->last_pid_recv, prev_fc->last_ack_sent,
- next_fc->queue_max, next_fc->queue_n);
- if (ack == prev_fc->last_ack_sent && GNUNET_NO == force)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending FWD ACK, not needed\n");
- return;
- }
-
- /* Check if message is already in queue */
- if (NULL != prev_fc->ack_msg)
- {
- if (GM_is_pid_bigger (ack, prev_fc->last_ack_sent))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " canceling old ACK\n");
- GMC_cancel (prev_fc->ack_msg);
- /* GMC_cancel triggers ack_sent(), which clears fc->ack_msg */
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " same ACK already in queue\n");
- return;
- }
- }
-
- prev_fc->last_ack_sent = ack;
-
- /* Build ACK message and send on connection */
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_ACK);
- msg.ack = htonl (ack);
- msg.cid = c->id;
-
- prev_fc->ack_msg = GMC_send_prebuilt_message (&msg.header,
- GNUNET_MESSAGE_TYPE_CADET_ACK,
- ack, c, !fwd, GNUNET_YES,
- &ack_sent, prev_fc);
-}
-
-
-/**
- * Callback called when a connection queued message is sent.
- *
- * Calculates the average time and connection packet tracking.
- *
- * @param cls Closure (ConnectionQueue Handle).
- * @param c Connection this message was on.
- * @param sent Was it really sent? (Could have been canceled)
- * @param type Type of message sent.
- * @param pid Packet ID, or 0 if not applicable (create, destroy, etc).
- * @param fwd Was this a FWD going message?
- * @param size Size of the message.
- * @param wait Time spent waiting for core (only the time for THIS message)
- */
-static void
-conn_message_sent (void *cls,
- struct CadetConnection *c, int sent,
- uint16_t type, uint32_t pid, int fwd, size_t size,
- struct GNUNET_TIME_Relative wait)
-{
- struct CadetConnectionPerformance *p;
- struct CadetFlowControl *fc;
- struct CadetConnectionQueue *q = cls;
- double usecsperbyte;
- int forced;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "connection message_sent\n");
-
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " %ssent %s %s\n",
- sent ? "" : "not ", GM_f2s (fwd), GM_m2s (type));
- if (NULL != q)
- {
- forced = q->forced;
- if (NULL != q->cont)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " calling cont\n");
- q->cont (q->cont_cls, c, q, type, fwd, size);
- }
- GNUNET_free (q);
- }
- else if (type == GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED)
- {
- /* If NULL == q and ENCRYPTED == type, message must have been ch_mngmnt */
- forced = GNUNET_YES;
- }
- else
- {
- forced = GNUNET_NO;
- }
- if (NULL == c)
- {
- GNUNET_break (type == GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN ||
- type == GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);
- LOG (GNUNET_ERROR_TYPE_ERROR, "Message %s sent on NULL connection!\n",
- GM_m2s (type));
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P- %p %u\n", c, c->pending_messages);
- c->pending_messages--;
- if (GNUNET_YES == c->destroy && 0 == c->pending_messages)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "! destroying connection!\n");
- GMC_destroy (c);
- return;
- }
- /* Send ACK if needed, after accounting for sent ID in fc->queue_n */
- switch (type)
- {
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK:
- c->maintenance_q = NULL;
- /* Don't trigger a keepalive for sent ACKs, only SYN and SYNACKs */
- if (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE == type || !fwd)
- schedule_next_keepalive (c, fwd);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
- if (GNUNET_YES == sent)
- {
- GNUNET_assert (NULL != q);
- fc->last_pid_sent = pid; // FIXME
- GMC_send_ack (c, fwd, GNUNET_NO);
- connection_reset_timeout (c, fwd);
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "! Q_N- %p %u\n", fc, fc->queue_n);
- if (GNUNET_NO == forced)
- {
- fc->queue_n--;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "! accounting pid %u\n",
- fc->last_pid_sent);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "! forced, Q_N not accounting pid %u\n",
- fc->last_pid_sent);
- }
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_KX:
- if (GNUNET_YES == sent)
- connection_reset_timeout (c, fwd);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_POLL:
- fc->poll_msg = NULL;
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_ACK:
- fc->ack_msg = NULL;
- break;
-
- default:
- break;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "! message sent!\n");
-
- if (NULL == c->perf)
- return; /* Only endpoints are interested in timing. */
-
- p = c->perf;
- usecsperbyte = ((double) wait.rel_value_us) / size;
- if (p->size == AVG_MSGS)
- {
- /* Array is full. Substract oldest value, add new one and store. */
- p->avg -= (p->usecsperbyte[p->idx] / AVG_MSGS);
- p->usecsperbyte[p->idx] = usecsperbyte;
- p->avg += (p->usecsperbyte[p->idx] / AVG_MSGS);
- }
- else
- {
- /* Array not yet full. Add current value to avg and store. */
- p->usecsperbyte[p->idx] = usecsperbyte;
- p->avg *= p->size;
- p->avg += p->usecsperbyte[p->idx];
- p->size++;
- p->avg /= p->size;
- }
- p->idx = (p->idx + 1) % AVG_MSGS;
-}
-
-
-/**
- * Get the previous hop in a connection
- *
- * @param c Connection.
- *
- * @return Previous peer in the connection.
- */
-static struct CadetPeer *
-get_prev_hop (const struct CadetConnection *c)
-{
- GNUNET_PEER_Id id;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " get prev hop %s [%u/%u]\n",
- GMC_2s (c), c->own_pos, c->path->length);
- if (0 == c->own_pos || c->path->length < 2)
- id = c->path->peers[0];
- else
- id = c->path->peers[c->own_pos - 1];
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " ID: %s (%u)\n",
- GNUNET_i2s (GNUNET_PEER_resolve2 (id)), id);
-
- return GMP_get_short (id);
-}
-
-
-/**
- * Get the next hop in a connection
- *
- * @param c Connection.
- *
- * @return Next peer in the connection.
- */
-static struct CadetPeer *
-get_next_hop (const struct CadetConnection *c)
-{
- GNUNET_PEER_Id id;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " get next hop %s [%u/%u]\n",
- GMC_2s (c), c->own_pos, c->path->length);
- if ((c->path->length - 1) == c->own_pos || c->path->length < 2)
- id = c->path->peers[c->path->length - 1];
- else
- id = c->path->peers[c->own_pos + 1];
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " ID: %s (%u)\n",
- GNUNET_i2s (GNUNET_PEER_resolve2 (id)), id);
-
- return GMP_get_short (id);
-}
-
-
-/**
- * Get the hop in a connection.
- *
- * @param c Connection.
- * @param fwd Next hop?
- *
- * @return Next peer in the connection.
- */
-static struct CadetPeer *
-get_hop (struct CadetConnection *c, int fwd)
-{
- if (fwd)
- return get_next_hop (c);
- return get_prev_hop (c);
-}
-
-
-/**
- * Is traffic coming from this sender 'FWD' traffic?
- *
- * @param c Connection to check.
- * @param sender Peer identity of neighbor.
- *
- * @return #GNUNET_YES in case the sender is the 'prev' hop and therefore
- * the traffic is 'FWD'.
- * #GNUNET_NO for BCK.
- * #GNUNET_SYSERR for errors.
- */
-static int
-is_fwd (const struct CadetConnection *c,
- const struct GNUNET_PeerIdentity *sender)
-{
- GNUNET_PEER_Id id;
-
- id = GNUNET_PEER_search (sender);
- if (GMP_get_short_id (get_prev_hop (c)) == id)
- return GNUNET_YES;
-
- if (GMP_get_short_id (get_next_hop (c)) == id)
- return GNUNET_NO;
-
- GNUNET_break (0);
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Sends a CONNECTION ACK message in reponse to a received CONNECTION_CREATE
- * or a first CONNECTION_ACK directed to us.
- *
- * @param connection Connection to confirm.
- * @param fwd Should we send it FWD? (root->dest)
- * (First (~SYNACK) goes BCK, second (~ACK) goes FWD)
- */
-static void
-send_connection_ack (struct CadetConnection *connection, int fwd)
-{
- struct CadetTunnel3 *t;
-
- t = connection->t;
- LOG (GNUNET_ERROR_TYPE_INFO, "===> {%14s ACK} on connection %s\n",
- GM_f2s (!fwd), GMC_2s (connection));
- GMP_queue_add (get_hop (connection, fwd), NULL,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK, 0,
- sizeof (struct GNUNET_CADET_ConnectionACK),
- connection, fwd, &conn_message_sent, NULL);
- connection->pending_messages++;
- if (CADET_TUNNEL3_NEW == GMT_get_cstate (t))
- GMT_change_cstate (t, CADET_TUNNEL3_WAITING);
- if (CADET_CONNECTION_READY != connection->state)
- connection_change_state (connection, CADET_CONNECTION_SENT);
-}
-
-
-/**
- * Send a notification that a connection is broken.
- *
- * @param c Connection that is broken.
- * @param id1 Peer that has disconnected.
- * @param id2 Peer that has disconnected.
- * @param fwd Direction towards which to send it.
- */
-static void
-send_broken (struct CadetConnection *c,
- const struct GNUNET_PeerIdentity *id1,
- const struct GNUNET_PeerIdentity *id2,
- int fwd)
-{
- struct GNUNET_CADET_ConnectionBroken msg;
-
- msg.header.size = htons (sizeof (struct GNUNET_CADET_ConnectionBroken));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
- msg.cid = c->id;
- msg.peer1 = *id1;
- msg.peer2 = *id2;
- GMC_send_prebuilt_message (&msg.header,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN, 0,
- c, fwd, GNUNET_YES, NULL, NULL);
-}
-
-
-/**
- * Send a notification that a connection is broken, when a connection
- * isn't even known to the local peer.
- *
- * @param connection_id Connection ID.
- * @param id1 Peer that has disconnected, probably local peer.
- * @param id2 Peer that has disconnected can be NULL if unknown.
- * @param peer Peer to notify (neighbor who sent the connection).
- */
-static void
-send_broken_unknown (const struct GNUNET_CADET_Hash *connection_id,
- const struct GNUNET_PeerIdentity *id1,
- const struct GNUNET_PeerIdentity *id2,
- const struct GNUNET_PeerIdentity *peer_id)
-{
- struct GNUNET_CADET_ConnectionBroken *msg;
- struct CadetPeer *neighbor;
-
- LOG (GNUNET_ERROR_TYPE_INFO, "===> BROKEN on unknown connection %s\n",
- GNUNET_h2s (GM_h2hc (connection_id)));
-
- msg = GNUNET_new (struct GNUNET_CADET_ConnectionBroken);
- msg->header.size = htons (sizeof (struct GNUNET_CADET_ConnectionBroken));
- msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
- msg->cid = *connection_id;
- msg->peer1 = *id1;
- if (NULL != id2)
- msg->peer2 = *id2;
- else
- memset (&msg->peer2, 0, sizeof (msg->peer2));
- neighbor = GMP_get (peer_id);
- GMP_queue_add (neighbor, msg,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN, 2,
- sizeof (struct GNUNET_CADET_ConnectionBroken),
- NULL, GNUNET_SYSERR, /* connection, fwd */
- NULL, NULL); /* continuation */
-}
-
-
-/**
- * Send keepalive packets for a connection.
- *
- * @param c Connection to keep alive..
- * @param fwd Is this a FWD keepalive? (owner -> dest).
- */
-static void
-send_connection_keepalive (struct CadetConnection *c, int fwd)
-{
- struct GNUNET_MessageHeader msg;
- struct CadetFlowControl *fc;
-
- LOG (GNUNET_ERROR_TYPE_INFO,
- "keepalive %s for connection %s\n",
- GM_f2s (fwd), GMC_2s (c));
-
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
- if (0 < fc->queue_n)
- {
- LOG (GNUNET_ERROR_TYPE_INFO, "not sending keepalive, traffic in queue\n");
- }
-
- GNUNET_STATISTICS_update (stats, "# keepalives sent", 1, GNUNET_NO);
-
- GNUNET_assert (NULL != c->t);
- msg.size = htons (sizeof (msg));
- msg.type = htons (GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE);
-
- GNUNET_assert (NULL ==
- GMT_send_prebuilt_message (&msg, c->t, c,
- GNUNET_NO, NULL, NULL));
-}
-
-
-/**
- * Send CONNECTION_{CREATE/ACK} packets for a connection.
- *
- * @param c Connection for which to send the message.
- * @param fwd If #GNUNET_YES, send CREATE, otherwise send ACK.
- */
-static void
-connection_recreate (struct CadetConnection *c, int fwd)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "sending connection recreate\n");
- if (fwd)
- GMC_send_create (c);
- else
- send_connection_ack (c, GNUNET_NO);
-}
-
-
-/**
- * Generic connection timer management.
- * Depending on the role of the peer in the connection will send the
- * appropriate message (build or keepalive)
- *
- * @param c Conncetion to maintain.
- * @param fwd Is FWD?
- */
-static void
-connection_maintain (struct CadetConnection *c, int fwd)
-{
- if (GNUNET_NO != c->destroy)
- return;
-
- if (CADET_TUNNEL3_SEARCHING == GMT_get_cstate (c->t))
- {
- /* TODO DHT GET with RO_BART */
- return;
- }
- switch (c->state)
- {
- case CADET_CONNECTION_NEW:
- GNUNET_break (0);
- /* fall-through */
- case CADET_CONNECTION_SENT:
- connection_recreate (c, fwd);
- break;
- case CADET_CONNECTION_READY:
- send_connection_keepalive (c, fwd);
- break;
- default:
- break;
- }
-}
-
-
-
-/**
- * Keep the connection alive.
- *
- * @param c Connection to keep alive.
- * @param fwd Direction.
- * @param shutdown Are we shutting down? (Don't send traffic)
- * Non-zero value for true, not necessarily GNUNET_YES.
- */
-static void
-connection_keepalive (struct CadetConnection *c, int fwd, int shutdown)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "%s keepalive for %s\n",
- GM_f2s (fwd), GMC_2s (c));
-
- if (fwd)
- c->fwd_maintenance_task = GNUNET_SCHEDULER_NO_TASK;
- else
- c->bck_maintenance_task = GNUNET_SCHEDULER_NO_TASK;
-
- if (GNUNET_NO != shutdown)
- return;
-
- connection_maintain (c, fwd);
-
- /* Next execution will be scheduled by message_sent */
-}
-
-
-/**
- * Keep the connection alive in the FWD direction.
- *
- * @param cls Closure (connection to keepalive).
- * @param tc TaskContext.
- */
-static void
-connection_fwd_keepalive (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- connection_keepalive ((struct CadetConnection *) cls,
- GNUNET_YES,
- tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN);
-}
-
-
-/**
- * Keep the connection alive in the BCK direction.
- *
- * @param cls Closure (connection to keepalive).
- * @param tc TaskContext.
- */
-static void
-connection_bck_keepalive (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- connection_keepalive ((struct CadetConnection *) cls,
- GNUNET_NO,
- tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN);
-}
-
-
-/**
- * Schedule next keepalive task, taking in consideration
- * the connection state and number of retries.
- *
- * If the peer is not the origin, do nothing.
- *
- * @param c Connection for which to schedule the next keepalive.
- * @param fwd Direction for the next keepalive.
- */
-static void
-schedule_next_keepalive (struct CadetConnection *c, int fwd)
-{
- struct GNUNET_TIME_Relative delay;
- GNUNET_SCHEDULER_TaskIdentifier *task_id;
- GNUNET_SCHEDULER_Task keepalive_task;
-
- if (GNUNET_NO == GMC_is_origin (c, fwd))
- return;
-
- /* Calculate delay to use, depending on the state of the connection */
- if (CADET_CONNECTION_READY == c->state)
- {
- delay = refresh_connection_time;
- }
- else
- {
- if (1 > c->create_retry)
- c->create_retry = 1;
- delay = GNUNET_TIME_relative_multiply (create_connection_time,
- c->create_retry);
- if (c->create_retry < 64)
- c->create_retry *= 2;
- }
-
- /* Select direction-dependent parameters */
- if (GNUNET_YES == fwd)
- {
- task_id = &c->fwd_maintenance_task;
- keepalive_task = &connection_fwd_keepalive;
- }
- else
- {
- task_id = &c->bck_maintenance_task;
- keepalive_task = &connection_bck_keepalive;
- }
-
- /* Check that no one scheduled it before us */
- if (GNUNET_SCHEDULER_NO_TASK != *task_id)
- {
- /* No need for a _break. It can happen for instance when sending a SYNACK
- * for a duplicate SYN: the first SYNACK scheduled the task. */
- GNUNET_SCHEDULER_cancel (*task_id);
- }
-
- /* Schedule the task */
- *task_id = GNUNET_SCHEDULER_add_delayed (delay, keepalive_task, c);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "next keepalive in %s\n",
- GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
-}
-
-
-/**
- * @brief Re-initiate traffic on this connection if necessary.
- *
- * Check if there is traffic queued towards this peer
- * and the core transmit handle is NULL (traffic was stalled).
- * If so, call core tmt rdy.
- *
- * @param c Connection on which initiate traffic.
- * @param fwd Is this about fwd traffic?
- */
-static void
-connection_unlock_queue (struct CadetConnection *c, int fwd)
-{
- struct CadetPeer *peer;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "connection_unlock_queue %s on %s\n",
- GM_f2s (fwd), GMC_2s (c));
-
- if (GMC_is_terminal (c, fwd))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " is terminal!\n");
- return;
- }
-
- peer = get_hop (c, fwd);
- GMP_queue_unlock (peer, c);
-}
-
-
-/**
- * Cancel all transmissions that belong to a certain connection.
- *
- * If the connection is scheduled for destruction and no more messages are
left,
- * the connection will be destroyed by the continuation call.
- *
- * @param c Connection which to cancel. Might be destroyed during this call.
- * @param fwd Cancel fwd traffic?
- */
-static void
-connection_cancel_queues (struct CadetConnection *c, int fwd)
-{
- struct CadetFlowControl *fc;
- struct CadetPeer *peer;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " *** Cancel %s queues for connection %s\n",
- GM_f2s (fwd), GMC_2s (c));
- if (NULL == c)
- {
- GNUNET_break (0);
- return;
- }
-
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
- if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task)
- {
- GNUNET_SCHEDULER_cancel (fc->poll_task);
- fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " *** Cancel POLL in ccq for fc %p\n", fc);
- }
- peer = get_hop (c, fwd);
- GMP_queue_cancel (peer, c);
-}
-
-
-/**
- * Function called if a connection has been stalled for a while,
- * possibly due to a missed ACK. Poll the neighbor about its ACK status.
- *
- * @param cls Closure (poll ctx).
- * @param tc TaskContext.
- */
-static void
-connection_poll (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
-
-
-/**
- * Callback called when a queued POLL message is sent.
- *
- * @param cls Closure (FC).
- * @param c Connection this message was on.
- * @param q Queue handler this call invalidates.
- * @param type Type of message sent.
- * @param fwd Was this a FWD going message?
- * @param size Size of the message.
- */
-static void
-poll_sent (void *cls,
- struct CadetConnection *c,
- struct CadetConnectionQueue *q,
- uint16_t type, int fwd, size_t size)
-{
- struct CadetFlowControl *fc = cls;
-
- if (2 == c->destroy)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL canceled on shutdown\n");
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " *** POLL sent for , scheduling new one!\n");
- fc->poll_msg = NULL;
- fc->poll_time = GNUNET_TIME_STD_BACKOFF (fc->poll_time);
- fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time,
- &connection_poll, fc);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " task %u\n", fc->poll_task);
-
-}
-
-/**
- * Function called if a connection has been stalled for a while,
- * possibly due to a missed ACK. Poll the neighbor about its ACK status.
- *
- * @param cls Closure (poll ctx).
- * @param tc TaskContext.
- */
-static void
-connection_poll (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct CadetFlowControl *fc = cls;
- struct GNUNET_CADET_Poll msg;
- struct CadetConnection *c;
-
- fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- {
- return;
- }
-
- c = fc->c;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " *** Polling connection %s %s\n",
- GMC_2s (c), fc == &c->fwd_fc ? "FWD" : "BCK");
-
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_POLL);
- msg.header.size = htons (sizeof (msg));
- msg.pid = htonl (fc->last_pid_sent);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " *** last pid sent: %u!\n",
fc->last_pid_sent);
- fc->poll_msg =
- GMC_send_prebuilt_message (&msg.header,
- GNUNET_MESSAGE_TYPE_CADET_POLL,
- fc->last_pid_sent,
- c, fc == &c->fwd_fc, GNUNET_YES,
- &poll_sent, fc);
-}
-
-
-/**
- * Timeout function due to lack of keepalive/traffic from the owner.
- * Destroys connection if called.
- *
- * @param cls Closure (connection to destroy).
- * @param tc TaskContext.
- */
-static void
-connection_fwd_timeout (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct CadetConnection *c = cls;
-
- c->fwd_maintenance_task = GNUNET_SCHEDULER_NO_TASK;
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- return;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s FWD timed out. Destroying.\n",
- GMC_2s (c));
- if (GMC_is_origin (c, GNUNET_YES)) /* If local, leave. */
- {
- GNUNET_break (0);
- return;
- }
-
- GMC_destroy (c);
-}
-
-
-/**
- * Timeout function due to lack of keepalive/traffic from the destination.
- * Destroys connection if called.
- *
- * @param cls Closure (connection to destroy).
- * @param tc TaskContext
- */
-static void
-connection_bck_timeout (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct CadetConnection *c = cls;
-
- c->bck_maintenance_task = GNUNET_SCHEDULER_NO_TASK;
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- return;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s BCK timed out. Destroying.\n",
- GMC_2s (c));
-
- if (GMC_is_origin (c, GNUNET_NO)) /* If local, leave. */
- {
- GNUNET_break (0);
- return;
- }
-
- GMC_destroy (c);
-}
-
-
-/**
- * Resets the connection timeout task, some other message has done the
- * task's job.
- * - For the first peer on the direction this means to send
- * a keepalive or a path confirmation message (either create or ACK).
- * - For all other peers, this means to destroy the connection,
- * due to lack of activity.
- * Starts the timeout if no timeout was running (connection just created).
- *
- * @param c Connection whose timeout to reset.
- * @param fwd Is this forward?
- *
- * TODO use heap to improve efficiency of scheduler.
- */
-static void
-connection_reset_timeout (struct CadetConnection *c, int fwd)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s reset timeout\n", GM_f2s (fwd));
-
- if (GMC_is_origin (c, fwd)) /* Startpoint */
- {
- schedule_next_keepalive (c, fwd);
- }
- else /* Relay, endpoint. */
- {
- struct GNUNET_TIME_Relative delay;
- GNUNET_SCHEDULER_TaskIdentifier *ti;
- GNUNET_SCHEDULER_Task f;
-
- ti = fwd ? &c->fwd_maintenance_task : &c->bck_maintenance_task;
-
- if (GNUNET_SCHEDULER_NO_TASK != *ti)
- GNUNET_SCHEDULER_cancel (*ti);
- delay = GNUNET_TIME_relative_multiply (refresh_connection_time, 4);
- f = fwd ? &connection_fwd_timeout : &connection_bck_timeout;
- *ti = GNUNET_SCHEDULER_add_delayed (delay, f, c);
- }
-}
-
-
-/**
- * Add the connection to the list of both neighbors.
- *
- * @param c Connection.
- *
- * @return #GNUNET_OK if everything went fine
- * #GNUNET_SYSERR if the was an error and @c c is malformed.
- */
-static int
-register_neighbors (struct CadetConnection *c)
-{
- struct CadetPeer *next_peer;
- struct CadetPeer *prev_peer;
-
- next_peer = get_next_hop (c);
- prev_peer = get_prev_hop (c);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "register neighbors for connection %s\n",
- GMC_2s (c));
- path_debug (c->path);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "own pos %u\n", c->own_pos);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "putting connection %s to next peer %p\n",
- GMC_2s (c), next_peer);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "next peer %p %s\n", next_peer, GMP_2s
(next_peer));
- LOG (GNUNET_ERROR_TYPE_DEBUG, "putting connection %s to prev peer %p\n",
- GMC_2s (c), prev_peer);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "prev peer %p %s\n", prev_peer, GMP_2s
(prev_peer));
-
- if (GNUNET_NO == GMP_is_neighbor (next_peer)
- || GNUNET_NO == GMP_is_neighbor (prev_peer))
- {
- if (GMC_is_origin (c, GNUNET_YES))
- GNUNET_STATISTICS_update (stats, "# local bad paths", 1, GNUNET_NO);
- GNUNET_STATISTICS_update (stats, "# bad paths", 1, GNUNET_NO);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " register neighbors failed\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, " prev: %s, neighbor?: %d\n",
- GMP_2s (prev_peer), GMP_is_neighbor (prev_peer));
- LOG (GNUNET_ERROR_TYPE_DEBUG, " next: %s, neighbor?: %d\n",
- GMP_2s (next_peer), GMP_is_neighbor (next_peer));
- return GNUNET_SYSERR;
- }
-
- GMP_add_connection (next_peer, c);
- GMP_add_connection (prev_peer, c);
-
- return GNUNET_OK;
-}
-
-
-/**
- * Remove the connection from the list of both neighbors.
- *
- * @param c Connection.
- */
-static void
-unregister_neighbors (struct CadetConnection *c)
-{
- struct CadetPeer *peer;
-
- peer = get_next_hop (c);
- if (GNUNET_OK != GMP_remove_connection (peer, c))
- {
- GNUNET_assert (CADET_CONNECTION_NEW == c->state
- || CADET_CONNECTION_DESTROYED == c->state);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate: %u\n", c->state);
- if (NULL != c->t) GMT_debug (c->t);
- }
-
- peer = get_prev_hop (c);
- if (GNUNET_OK != GMP_remove_connection (peer, c))
- {
- GNUNET_assert (CADET_CONNECTION_NEW == c->state
- || CADET_CONNECTION_DESTROYED == c->state);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate: %u\n", c->state);
- if (NULL != c->t) GMT_debug (c->t);
- }
-}
-
-
-/**
- * Bind the connection to the peer and the tunnel to that peer.
- *
- * If the peer has no tunnel, create one. Update tunnel and connection
- * data structres to reflect new status.
- *
- * @param c Connection.
- * @param peer Peer.
- */
-static void
-add_to_peer (struct CadetConnection *c, struct CadetPeer *peer)
-{
- GMP_add_tunnel (peer);
- c->t = GMP_get_tunnel (peer);
- GMT_add_connection (c->t, c);
-}
-
-
-/**
- * Builds a path from a PeerIdentity array.
- *
- * @param peers PeerIdentity array.
- * @param size Size of the @c peers array.
- * @param own_pos Output parameter: own position in the path.
- *
- * @return Fixed and shortened path.
- */
-static struct CadetPeerPath *
-build_path_from_peer_ids (struct GNUNET_PeerIdentity *peers,
- unsigned int size,
- unsigned int *own_pos)
-{
- struct CadetPeerPath *path;
- GNUNET_PEER_Id shortid;
- unsigned int i;
- unsigned int j;
- unsigned int offset;
-
- /* Create path */
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Creating path...\n");
- path = path_new (size);
- *own_pos = 0;
- offset = 0;
- for (i = 0; i < size; i++)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " - %u: taking %s\n",
- i, GNUNET_i2s (&peers[i]));
- shortid = GNUNET_PEER_intern (&peers[i]);
-
- /* Check for loops / duplicates */
- for (j = 0; j < i - offset; j++)
- {
- if (path->peers[j] == shortid)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " already exists at pos %u\n", j);
- offset = i - j;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " offset now %u\n", offset);
- GNUNET_PEER_change_rc (shortid, -1);
- }
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " storing at %u\n", i - offset);
- path->peers[i - offset] = shortid;
- if (path->peers[i - offset] == myid)
- *own_pos = i - offset;
- }
- path->length -= offset;
-
- if (path->peers[*own_pos] != myid)
- {
- /* create path: self not found in path through self */
- GNUNET_break_op (0);
- path_destroy (path);
- return NULL;
- }
-
- return path;
-}
-
-
-/**
- * Log receipt of message on stderr (INFO level).
- *
- * @param message Message received.
- * @param peer Peer who sent the message.
- * @param hash Connection ID.
- */
-static void
-log_message (const struct GNUNET_MessageHeader *message,
- const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_CADET_Hash *hash)
-{
- LOG (GNUNET_ERROR_TYPE_INFO, "<-- %s on connection %s from %s\n",
- GM_m2s (ntohs (message->type)), GNUNET_h2s (GM_h2hc (hash)),
- GNUNET_i2s (peer));
-}
-
-/******************************************************************************/
-/******************************** API
***********************************/
-/******************************************************************************/
-
-/**
- * Core handler for connection creation.
- *
- * @param cls Closure (unused).
- * @param peer Sender (neighbor).
- * @param message Message.
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-GMC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
-{
- struct GNUNET_CADET_ConnectionCreate *msg;
- struct GNUNET_PeerIdentity *id;
- struct GNUNET_CADET_Hash *cid;
- struct CadetPeerPath *path;
- struct CadetPeer *dest_peer;
- struct CadetPeer *orig_peer;
- struct CadetConnection *c;
- unsigned int own_pos;
- uint16_t size;
-
- /* Check size */
- size = ntohs (message->size);
- if (size < sizeof (struct GNUNET_CADET_ConnectionCreate))
- {
- GNUNET_break_op (0);
- return GNUNET_OK;
- }
-
- /* Calculate hops */
- size -= sizeof (struct GNUNET_CADET_ConnectionCreate);
- if (size % sizeof (struct GNUNET_PeerIdentity))
- {
- GNUNET_break_op (0);
- return GNUNET_OK;
- }
- size /= sizeof (struct GNUNET_PeerIdentity);
- if (1 > size)
- {
- GNUNET_break_op (0);
- return GNUNET_OK;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " path has %u hops.\n", size);
-
- /* Get parameters */
- msg = (struct GNUNET_CADET_ConnectionCreate *) message;
- cid = &msg->cid;
- log_message (message, peer, cid);
- id = (struct GNUNET_PeerIdentity *) &msg[1];
- LOG (GNUNET_ERROR_TYPE_DEBUG, " origin: %s\n", GNUNET_i2s (id));
-
- /* Create connection */
- c = connection_get (cid);
- if (NULL == c)
- {
- path = build_path_from_peer_ids ((struct GNUNET_PeerIdentity *) &msg[1],
- size, &own_pos);
- if (NULL == path)
- return GNUNET_OK;
- if (0 == own_pos)
- {
- GNUNET_break_op (0);
- path_destroy (path);
- return GNUNET_OK;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Own position: %u\n", own_pos);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Creating connection\n");
- c = GMC_new (cid, NULL, path_duplicate (path), own_pos);
- if (NULL == c)
- {
- if (path->length - 1 == own_pos)
- {
- /* If we are destination, why did the creation fail? */
- GNUNET_break (0);
- return GNUNET_OK;
- }
- send_broken_unknown (cid, &my_full_id,
- GNUNET_PEER_resolve2 (path->peers[own_pos + 1]),
- peer);
- path_destroy (path);
- return GNUNET_OK;
- }
- GMP_add_path_to_all (path, GNUNET_NO);
- connection_reset_timeout (c, GNUNET_YES);
- }
- else
- {
- path = path_duplicate (c->path);
- }
- if (CADET_CONNECTION_NEW == c->state)
- connection_change_state (c, CADET_CONNECTION_SENT);
-
- /* Remember peers */
- dest_peer = GMP_get (&id[size - 1]);
- orig_peer = GMP_get (&id[0]);
-
- /* Is it a connection to us? */
- if (c->own_pos == path->length - 1)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " It's for us!\n");
- GMP_add_path_to_origin (orig_peer, path_duplicate (path), GNUNET_YES);
-
- add_to_peer (c, orig_peer);
- if (CADET_TUNNEL3_NEW == GMT_get_cstate (c->t))
- GMT_change_cstate (c->t, CADET_TUNNEL3_WAITING);
-
- send_connection_ack (c, GNUNET_NO);
- if (CADET_CONNECTION_SENT == c->state)
- connection_change_state (c, CADET_CONNECTION_ACK);
- }
- else
- {
- /* It's for somebody else! Retransmit. */
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Retransmitting.\n");
- GMP_add_path (dest_peer, path_duplicate (path), GNUNET_NO);
- GMP_add_path_to_origin (orig_peer, path_duplicate (path), GNUNET_NO);
- GMC_send_prebuilt_message (message,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, 0,
- c, GNUNET_YES, GNUNET_YES,
- NULL, NULL);
- }
- path_destroy (path);
- return GNUNET_OK;
-}
-
-
-/**
- * Core handler for path confirmations.
- *
- * @param cls closure
- * @param message message
- * @param peer peer identity this notification is about
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-GMC_handle_confirm (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
-{
- struct GNUNET_CADET_ConnectionACK *msg;
- struct CadetConnection *c;
- struct CadetPeerPath *p;
- struct CadetPeer *pi;
- enum CadetConnectionState oldstate;
- int fwd;
-
- msg = (struct GNUNET_CADET_ConnectionACK *) message;
- log_message (message, peer, &msg->cid);
- c = connection_get (&msg->cid);
- if (NULL == c)
- {
- GNUNET_STATISTICS_update (stats, "# control on unknown connection",
- 1, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " don't know the connection!\n");
- send_broken_unknown (&msg->cid, &my_full_id, NULL, peer);
- return GNUNET_OK;
- }
-
- if (GNUNET_NO != c->destroy)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " connection being destroyed\n");
- return GNUNET_OK;
- }
-
- oldstate = c->state;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " via peer %s\n", GNUNET_i2s (peer));
- pi = GMP_get (peer);
- if (get_next_hop (c) == pi)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " SYNACK\n");
- fwd = GNUNET_NO;
- if (CADET_CONNECTION_SENT == oldstate)
- connection_change_state (c, CADET_CONNECTION_ACK);
- }
- else if (get_prev_hop (c) == pi)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " ACK\n");
- fwd = GNUNET_YES;
- connection_change_state (c, CADET_CONNECTION_READY);
- }
- else
- {
- GNUNET_break_op (0);
- return GNUNET_OK;
- }
-
- connection_reset_timeout (c, fwd);
-
- /* Add path to peers? */
- p = c->path;
- if (NULL != p)
- {
- GMP_add_path_to_all (p, GNUNET_YES);
- }
- else
- {
- GNUNET_break (0);
- }
-
- /* Message for us as creator? */
- if (GMC_is_origin (c, GNUNET_YES))
- {
- if (GNUNET_NO != fwd)
- {
- GNUNET_break_op (0);
- return GNUNET_OK;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Connection (SYN)ACK for us!\n");
-
- /* If just created, cancel the short timeout and start a long one */
- if (CADET_CONNECTION_SENT == oldstate)
- connection_reset_timeout (c, GNUNET_YES);
-
- /* Change connection state */
- connection_change_state (c, CADET_CONNECTION_READY);
- send_connection_ack (c, GNUNET_YES);
-
- /* Change tunnel state, trigger KX */
- if (CADET_TUNNEL3_WAITING == GMT_get_cstate (c->t))
- GMT_change_cstate (c->t, CADET_TUNNEL3_READY);
-
- return GNUNET_OK;
- }
-
- /* Message for us as destination? */
- if (GMC_is_terminal (c, GNUNET_YES))
- {
- if (GNUNET_YES != fwd)
- {
- GNUNET_break_op (0);
- return GNUNET_OK;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Connection ACK for us!\n");
-
- /* If just created, cancel the short timeout and start a long one */
- if (CADET_CONNECTION_ACK == oldstate)
- connection_reset_timeout (c, GNUNET_NO);
-
- /* Change tunnel state */
- if (CADET_TUNNEL3_WAITING == GMT_get_cstate (c->t))
- GMT_change_cstate (c->t, CADET_TUNNEL3_READY);
-
- return GNUNET_OK;
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n");
- GMC_send_prebuilt_message (message,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK, 0,
- c, fwd, GNUNET_YES, NULL, NULL);
- return GNUNET_OK;
-}
-
-
-/**
- * Core handler for notifications of broken connections.
- *
- * @param cls Closure (unused).
- * @param id Peer identity of sending neighbor.
- * @param message Message.
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-GMC_handle_broken (void* cls,
- const struct GNUNET_PeerIdentity* id,
- const struct GNUNET_MessageHeader* message)
-{
- struct GNUNET_CADET_ConnectionBroken *msg;
- struct CadetConnection *c;
- int fwd;
-
- msg = (struct GNUNET_CADET_ConnectionBroken *) message;
- log_message (message, id, &msg->cid);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n",
- GNUNET_i2s (&msg->peer1));
- LOG (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n",
- GNUNET_i2s (&msg->peer2));
- c = connection_get (&msg->cid);
- if (NULL == c)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate CONNECTION_BROKEN\n");
- return GNUNET_OK;
- }
-
- fwd = is_fwd (c, id);
- if (GMC_is_terminal (c, fwd))
- {
- struct GNUNET_MessageHeader *out_msg;
- struct CadetPeer *neighbor;
- struct CadetPeer *endpoint;
-
- neighbor = get_hop (c, !fwd);
- endpoint = GMP_get_short (c->path->peers[c->path->length - 1]);
- path_invalidate (c->path);
- GMP_notify_broken_link (endpoint, &msg->peer1, &msg->peer2);
- c->state = CADET_CONNECTION_DESTROYED;
- while (NULL != (out_msg = GMP_connection_pop (neighbor, c)))
- {
- GNUNET_assert (NULL ==
- GMT_send_prebuilt_message (out_msg, c->t, NULL,
GNUNET_YES,
- NULL, NULL));
- }
-
- GMC_destroy (c);
- }
- else
- {
- GMC_send_prebuilt_message (message,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN, 0,
- c, fwd, GNUNET_YES, NULL, NULL);
- c->destroy = GNUNET_YES;
- connection_cancel_queues (c, !fwd);
- }
-
- return GNUNET_OK;
-
-}
-
-
-/**
- * Core handler for tunnel destruction
- *
- * @param cls Closure (unused).
- * @param peer Peer identity of sending neighbor.
- * @param message Message.
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-GMC_handle_destroy (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
-{
- struct GNUNET_CADET_ConnectionDestroy *msg;
- struct CadetConnection *c;
- int fwd;
-
- msg = (struct GNUNET_CADET_ConnectionDestroy *) message;
- log_message (message, peer, &msg->cid);
- c = connection_get (&msg->cid);
- if (NULL == c)
- {
- /* Probably already got the message from another path,
- * destroyed the tunnel and retransmitted to children.
- * Safe to ignore.
- */
- GNUNET_STATISTICS_update (stats, "# control on unknown connection",
- 1, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " connection unknown: already
destroyed?\n");
- return GNUNET_OK;
- }
- fwd = is_fwd (c, peer);
- if (GNUNET_SYSERR == fwd)
- {
- GNUNET_break_op (0); /* FIXME */
- return GNUNET_OK;
- }
- if (GNUNET_NO == GMC_is_terminal (c, fwd))
- GMC_send_prebuilt_message (message,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY, 0,
- c, fwd, GNUNET_YES, NULL, NULL);
- else if (0 == c->pending_messages)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " directly destroying connection!\n");
- GMC_destroy (c);
- return GNUNET_OK;
- }
- c->destroy = GNUNET_YES;
- c->state = CADET_CONNECTION_DESTROYED;
- if (NULL != c->t)
- {
- GMT_remove_connection (c->t, c);
- c->t = NULL;
- }
-
- return GNUNET_OK;
-}
-
-/**
- * Generic handler for cadet network encrypted traffic.
- *
- * @param peer Peer identity this notification is about.
- * @param msg Encrypted message.
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-static int
-handle_cadet_encrypted (const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_CADET_Encrypted *msg)
-{
- struct CadetConnection *c;
- struct CadetPeer *neighbor;
- struct CadetFlowControl *fc;
- GNUNET_PEER_Id peer_id;
- uint32_t pid;
- uint32_t ttl;
- size_t size;
- int fwd;
-
- log_message (&msg->header, peer, &msg->cid);
-
- /* Check size */
- size = ntohs (msg->header.size);
- if (size <
- sizeof (struct GNUNET_CADET_Encrypted) +
- sizeof (struct GNUNET_MessageHeader))
- {
- GNUNET_break_op (0);
- return GNUNET_OK;
- }
-
- /* Check connection */
- c = connection_get (&msg->cid);
- if (NULL == c)
- {
- GNUNET_STATISTICS_update (stats, "# unknown connection", 1, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "enc on unknown connection %s\n",
- GNUNET_h2s (GM_h2hc (&msg->cid)));
- send_broken_unknown (&msg->cid, &my_full_id, NULL, peer);
- return GNUNET_OK;
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " connection %s\n", GMC_2s (c));
-
- /* Check if origin is as expected */
- neighbor = get_prev_hop (c);
- peer_id = GNUNET_PEER_search (peer);
- if (peer_id == GMP_get_short_id (neighbor))
- {
- fwd = GNUNET_YES;
- }
- else
- {
- neighbor = get_next_hop (c);
- if (peer_id == GMP_get_short_id (neighbor))
- {
- fwd = GNUNET_NO;
- }
- else
- {
- /* Unexpected peer sending traffic on a connection. */
- GNUNET_break_op (0);
- return GNUNET_OK;
- }
- }
-
- /* Check PID */
- fc = fwd ? &c->bck_fc : &c->fwd_fc;
- pid = ntohl (msg->pid);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " PID %u (expected %u+)\n",
- pid, fc->last_pid_recv + 1);
- if (GM_is_pid_bigger (pid, fc->last_ack_sent))
- {
- GNUNET_STATISTICS_update (stats, "# unsolicited message", 1, GNUNET_NO);
- GNUNET_break_op (0);
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "Received PID %u, (prev %u), ACK %u\n",
- pid, fc->last_pid_recv, fc->last_ack_sent);
- return GNUNET_OK;
- }
- if (GNUNET_NO == GM_is_pid_bigger (pid, fc->last_pid_recv))
- {
- GNUNET_STATISTICS_update (stats, "# duplicate PID", 1, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " PID %u not expected (%u+), dropping!\n",
- pid, fc->last_pid_recv + 1);
- return GNUNET_OK;
- }
- if (CADET_CONNECTION_SENT == c->state || CADET_CONNECTION_ACK == c->state)
- connection_change_state (c, CADET_CONNECTION_READY);
- connection_reset_timeout (c, fwd);
- fc->last_pid_recv = pid;
-
- /* Is this message for us? */
- if (GMC_is_terminal (c, fwd))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " message for us!\n");
- GNUNET_STATISTICS_update (stats, "# messages received", 1, GNUNET_NO);
-
- if (NULL == c->t)
- {
- GNUNET_break (GNUNET_NO != c->destroy);
- return GNUNET_OK;
- }
- fc->last_pid_recv = pid;
- GMT_handle_encrypted (c->t, msg);
- GMC_send_ack (c, fwd, GNUNET_NO);
- return GNUNET_OK;
- }
-
- /* Message not for us: forward to next hop */
- LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n");
- ttl = ntohl (msg->ttl);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " ttl: %u\n", ttl);
- if (ttl == 0)
- {
- GNUNET_STATISTICS_update (stats, "# TTL drops", 1, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_WARNING, " TTL is 0, DROPPING!\n");
- GMC_send_ack (c, fwd, GNUNET_NO);
- return GNUNET_OK;
- }
-
- GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO);
- GMC_send_prebuilt_message (&msg->header,
- GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED, 0,
- c, fwd, GNUNET_NO, NULL, NULL);
-
- return GNUNET_OK;
-}
-
-/**
- * Generic handler for cadet network encrypted traffic.
- *
- * @param peer Peer identity this notification is about.
- * @param msg Encrypted message.
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-static int
-handle_cadet_kx (const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_CADET_KX *msg)
-{
- struct CadetConnection *c;
- struct CadetPeer *neighbor;
- GNUNET_PEER_Id peer_id;
- size_t size;
- int fwd;
-
- log_message (&msg->header, peer, &msg->cid);
-
- /* Check size */
- size = ntohs (msg->header.size);
- if (size <
- sizeof (struct GNUNET_CADET_KX) +
- sizeof (struct GNUNET_MessageHeader))
- {
- GNUNET_break_op (0);
- return GNUNET_OK;
- }
-
- /* Check connection */
- c = connection_get (&msg->cid);
- if (NULL == c)
- {
- GNUNET_STATISTICS_update (stats, "# unknown connection", 1, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "kx on unknown connection %s\n",
- GNUNET_h2s (GM_h2hc (&msg->cid)));
- send_broken_unknown (&msg->cid, &my_full_id, NULL, peer);
- return GNUNET_OK;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " on connection %s\n", GMC_2s (c));
-
- /* Check if origin is as expected */
- neighbor = get_prev_hop (c);
- peer_id = GNUNET_PEER_search (peer);
- if (peer_id == GMP_get_short_id (neighbor))
- {
- fwd = GNUNET_YES;
- }
- else
- {
- neighbor = get_next_hop (c);
- if (peer_id == GMP_get_short_id (neighbor))
- {
- fwd = GNUNET_NO;
- }
- else
- {
- /* Unexpected peer sending traffic on a connection. */
- GNUNET_break_op (0);
- return GNUNET_OK;
- }
- }
-
- /* Count as connection confirmation. */
- if (CADET_CONNECTION_SENT == c->state || CADET_CONNECTION_ACK == c->state)
- {
- connection_change_state (c, CADET_CONNECTION_READY);
- if (NULL != c->t)
- {
- if (CADET_TUNNEL3_WAITING == GMT_get_cstate (c->t))
- GMT_change_cstate (c->t, CADET_TUNNEL3_READY);
- }
- }
- connection_reset_timeout (c, fwd);
-
- /* Is this message for us? */
- if (GMC_is_terminal (c, fwd))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " message for us!\n");
- GNUNET_STATISTICS_update (stats, "# messages received", 1, GNUNET_NO);
- if (NULL == c->t)
- {
- GNUNET_break (0);
- return GNUNET_OK;
- }
- GMT_handle_kx (c->t, &msg[1].header);
- return GNUNET_OK;
- }
-
- /* Message not for us: forward to next hop */
- LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n");
- GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO);
- GMC_send_prebuilt_message (&msg->header, GNUNET_MESSAGE_TYPE_CADET_KX, 0,
- c, fwd, GNUNET_NO, NULL, NULL);
-
- return GNUNET_OK;
-}
-
-
-/**
- * Core handler for encrypted cadet network traffic (channel mgmt, data).
- *
- * @param cls Closure (unused).
- * @param message Message received.
- * @param peer Peer who sent the message.
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-GMC_handle_encrypted (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
-{
- return handle_cadet_encrypted (peer,
- (struct GNUNET_CADET_Encrypted *)message);
-}
-
-
-/**
- * Core handler for key exchange traffic (ephemeral key, ping, pong).
- *
- * @param cls Closure (unused).
- * @param message Message received.
- * @param peer Peer who sent the message.
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-GMC_handle_kx (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
-{
- return handle_cadet_kx (peer,
- (struct GNUNET_CADET_KX *) message);
-}
-
-
-/**
- * Core handler for cadet network traffic point-to-point acks.
- *
- * @param cls closure
- * @param message message
- * @param peer peer identity this notification is about
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-GMC_handle_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
-{
- struct GNUNET_CADET_ACK *msg;
- struct CadetConnection *c;
- struct CadetFlowControl *fc;
- GNUNET_PEER_Id id;
- uint32_t ack;
- int fwd;
-
- msg = (struct GNUNET_CADET_ACK *) message;
- log_message (message, peer, &msg->cid);
- c = connection_get (&msg->cid);
- if (NULL == c)
- {
- GNUNET_STATISTICS_update (stats, "# ack on unknown connection", 1,
- GNUNET_NO);
- send_broken_unknown (&msg->cid, &my_full_id, NULL, peer);
- return GNUNET_OK;
- }
-
- /* Is this a forward or backward ACK? */
- id = GNUNET_PEER_search (peer);
- if (GMP_get_short_id (get_next_hop (c)) == id)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD ACK\n");
- fc = &c->fwd_fc;
- fwd = GNUNET_YES;
- }
- else if (GMP_get_short_id (get_prev_hop (c)) == id)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK ACK\n");
- fc = &c->bck_fc;
- fwd = GNUNET_NO;
- }
- else
- {
- GNUNET_break_op (0);
- return GNUNET_OK;
- }
-
- ack = ntohl (msg->ack);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " ACK %u (was %u)\n",
- ack, fc->last_ack_recv);
- if (GM_is_pid_bigger (ack, fc->last_ack_recv))
- fc->last_ack_recv = ack;
-
- /* Cancel polling if the ACK is big enough. */
- if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task &&
- GM_is_pid_bigger (fc->last_ack_recv, fc->last_pid_sent))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Cancel poll\n");
- GNUNET_SCHEDULER_cancel (fc->poll_task);
- fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
- fc->poll_time = GNUNET_TIME_UNIT_SECONDS;
- }
-
- connection_unlock_queue (c, fwd);
-
- return GNUNET_OK;
-}
-
-
-/**
- * Core handler for cadet network traffic point-to-point ack polls.
- *
- * @param cls closure
- * @param message message
- * @param peer peer identity this notification is about
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-GMC_handle_poll (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
-{
- struct GNUNET_CADET_Poll *msg;
- struct CadetConnection *c;
- struct CadetFlowControl *fc;
- GNUNET_PEER_Id id;
- uint32_t pid;
- int fwd;
-
- msg = (struct GNUNET_CADET_Poll *) message;
- log_message (message, peer, &msg->cid);
- c = connection_get (&msg->cid);
- if (NULL == c)
- {
- GNUNET_STATISTICS_update (stats, "# poll on unknown connection", 1,
- GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL message on unknown connection %s!\n",
- GNUNET_h2s (GM_h2hc (&msg->cid)));
- send_broken_unknown (&msg->cid, &my_full_id, NULL, peer);
- return GNUNET_OK;
- }
-
- /* Is this a forward or backward ACK?
- * Note: a poll should never be needed in a loopback case,
- * since there is no possiblility of packet loss there, so
- * this way of discerining FWD/BCK should not be a problem.
- */
- id = GNUNET_PEER_search (peer);
- if (GMP_get_short_id (get_next_hop (c)) == id)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD FC\n");
- fc = &c->fwd_fc;
- }
- else if (GMP_get_short_id (get_prev_hop (c)) == id)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK FC\n");
- fc = &c->bck_fc;
- }
- else
- {
- GNUNET_break_op (0);
- return GNUNET_OK;
- }
-
- pid = ntohl (msg->pid);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " PID %u, OLD %u\n", pid, fc->last_pid_recv);
- fc->last_pid_recv = pid;
- fwd = fc == &c->bck_fc;
- GMC_send_ack (c, fwd, GNUNET_YES);
-
- return GNUNET_OK;
-}
-
-
-/**
- * Send an ACK on the appropriate connection/channel, depending on
- * the direction and the position of the peer.
- *
- * @param c Which connection to send the hop-by-hop ACK.
- * @param fwd Is this a fwd ACK? (will go dest->root).
- * @param force Send the ACK even if suboptimal (e.g. requested by POLL).
- */
-void
-GMC_send_ack (struct CadetConnection *c, int fwd, int force)
-{
- unsigned int buffer;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "GMC send %s ACK on %s\n",
- GM_f2s (fwd), GMC_2s (c));
-
- if (NULL == c)
- {
- GNUNET_break (0);
- return;
- }
-
- if (GNUNET_NO != c->destroy)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " being destroyed, why bother...\n");
- return;
- }
-
- /* Get available buffer space */
- if (GMC_is_terminal (c, fwd))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " getting from all channels\n");
- buffer = GMT_get_channels_buffer (c->t);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " getting from one connection\n");
- buffer = GMC_get_buffer (c, fwd);
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer available: %u\n", buffer);
- if (0 == buffer && GNUNET_NO == force)
- return;
-
- /* Send available buffer space */
- if (GMC_is_origin (c, fwd))
- {
- GNUNET_assert (NULL != c->t);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on channels...\n");
- GMT_unchoke_channels (c->t);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " sending on connection\n");
- send_ack (c, buffer, fwd, force);
- }
-}
-
-
-/**
- * Initialize the connections subsystem
- *
- * @param c Configuration handle.
- */
-void
-GMC_init (const struct GNUNET_CONFIGURATION_Handle *c)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_MSGS_QUEUE",
- &max_msgs_queue))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "CADET", "MAX_MSGS_QUEUE", "MISSING");
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_CONNECTIONS",
- &max_connections))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "CADET", "MAX_CONNECTIONS", "MISSING");
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (c, "CADET",
"REFRESH_CONNECTION_TIME",
- &refresh_connection_time))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "CADET", "REFRESH_CONNECTION_TIME", "MISSING");
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- create_connection_time = GNUNET_TIME_UNIT_SECONDS;
- connections = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_NO);
-}
-
-
-/**
- * Destroy each connection on shutdown.
- *
- * @param cls Closure (unused).
- * @param key Current key code (CID, unused).
- * @param value Value in the hash map (connection)
- *
- * @return #GNUNET_YES, because we should continue to iterate,
- */
-static int
-shutdown_iterator (void *cls,
- const struct GNUNET_HashCode *key,
- void *value)
-{
- struct CadetConnection *c = value;
-
- GMC_destroy (c);
- return GNUNET_YES;
-}
-
-
-/**
- * Shut down the connections subsystem.
- */
-void
-GMC_shutdown (void)
-{
- GNUNET_CONTAINER_multihashmap_iterate (connections, &shutdown_iterator,
NULL);
- GNUNET_CONTAINER_multihashmap_destroy (connections);
- connections = NULL;
-}
-
-
-struct CadetConnection *
-GMC_new (const struct GNUNET_CADET_Hash *cid,
- struct CadetTunnel3 *t,
- struct CadetPeerPath *p,
- unsigned int own_pos)
-{
- struct CadetConnection *c;
-
- c = GNUNET_new (struct CadetConnection);
- c->id = *cid;
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CONTAINER_multihashmap_put (connections,
- GMC_get_h (c), c,
-
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
- fc_init (&c->fwd_fc);
- fc_init (&c->bck_fc);
- c->fwd_fc.c = c;
- c->bck_fc.c = c;
-
- c->t = t;
- GNUNET_assert (own_pos <= p->length - 1);
- c->own_pos = own_pos;
- c->path = p;
- p->c = c;
-
- if (GNUNET_OK != register_neighbors (c))
- {
- if (0 == own_pos)
- {
- path_invalidate (c->path);
- c->t = NULL;
- c->path = NULL;
- }
- GMC_destroy (c);
- return NULL;
- }
-
- return c;
-}
-
-
-void
-GMC_destroy (struct CadetConnection *c)
-{
- if (NULL == c)
- {
- GNUNET_break (0);
- return;
- }
-
- if (2 == c->destroy) /* cancel queues -> GMP_queue_cancel -> q_destroy -> */
- return; /* -> message_sent -> GMC_destroy. Don't loop. */
- c->destroy = 2;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying connection %s\n", GMC_2s (c));
- LOG (GNUNET_ERROR_TYPE_DEBUG, " fc's f: %p, b: %p\n",
- &c->fwd_fc, &c->bck_fc);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " fc tasks f: %u, b: %u\n",
- c->fwd_fc.poll_task, c->bck_fc.poll_task);
-
- /* Cancel all traffic */
- if (NULL != c->path)
- {
- connection_cancel_queues (c, GNUNET_YES);
- connection_cancel_queues (c, GNUNET_NO);
- unregister_neighbors (c);
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " fc tasks f: %u, b: %u\n",
- c->fwd_fc.poll_task, c->bck_fc.poll_task);
-
- /* Cancel maintainance task (keepalive/timeout) */
- if (NULL != c->fwd_fc.poll_msg)
- {
- GMC_cancel (c->fwd_fc.poll_msg);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL msg FWD canceled\n");
- }
- if (NULL != c->bck_fc.poll_msg)
- {
- GMC_cancel (c->bck_fc.poll_msg);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL msg BCK canceled\n");
- }
-
- /* Delete from tunnel */
- if (NULL != c->t)
- GMT_remove_connection (c->t, c);
-
- if (GNUNET_NO == GMC_is_origin (c, GNUNET_YES) && NULL != c->path)
- path_destroy (c->path);
- if (GNUNET_SCHEDULER_NO_TASK != c->fwd_maintenance_task)
- GNUNET_SCHEDULER_cancel (c->fwd_maintenance_task);
- if (GNUNET_SCHEDULER_NO_TASK != c->bck_maintenance_task)
- GNUNET_SCHEDULER_cancel (c->bck_maintenance_task);
- if (GNUNET_SCHEDULER_NO_TASK != c->fwd_fc.poll_task)
- {
- GNUNET_SCHEDULER_cancel (c->fwd_fc.poll_task);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL FWD canceled\n");
- }
- if (GNUNET_SCHEDULER_NO_TASK != c->bck_fc.poll_task)
- {
- GNUNET_SCHEDULER_cancel (c->bck_fc.poll_task);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL BCK canceled\n");
- }
-
- GNUNET_break (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_remove (connections,
- GMC_get_h (c), c));
-
- GNUNET_STATISTICS_update (stats, "# connections", -1, GNUNET_NO);
- GNUNET_free (c);
-}
-
-/**
- * Get the connection ID.
- *
- * @param c Connection to get the ID from.
- *
- * @return ID of the connection.
- */
-const struct GNUNET_CADET_Hash *
-GMC_get_id (const struct CadetConnection *c)
-{
- return &c->id;
-}
-
-
-/**
- * Get the connection ID.
- *
- * @param c Connection to get the ID from.
- *
- * @return ID of the connection.
- */
-const struct GNUNET_HashCode *
-GMC_get_h (const struct CadetConnection *c)
-{
- return GM_h2hc (&c->id);
-}
-
-
-/**
- * Get the connection path.
- *
- * @param c Connection to get the path from.
- *
- * @return path used by the connection.
- */
-const struct CadetPeerPath *
-GMC_get_path (const struct CadetConnection *c)
-{
- if (GNUNET_NO == c->destroy)
- return c->path;
- return NULL;
-}
-
-
-/**
- * Get the connection state.
- *
- * @param c Connection to get the state from.
- *
- * @return state of the connection.
- */
-enum CadetConnectionState
-GMC_get_state (const struct CadetConnection *c)
-{
- return c->state;
-}
-
-/**
- * Get the connection tunnel.
- *
- * @param c Connection to get the tunnel from.
- *
- * @return tunnel of the connection.
- */
-struct CadetTunnel3 *
-GMC_get_tunnel (const struct CadetConnection *c)
-{
- return c->t;
-}
-
-
-/**
- * Get free buffer space in a connection.
- *
- * @param c Connection.
- * @param fwd Is query about FWD traffic?
- *
- * @return Free buffer space [0 - max_msgs_queue/max_connections]
- */
-unsigned int
-GMC_get_buffer (struct CadetConnection *c, int fwd)
-{
- struct CadetFlowControl *fc;
-
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
-
- return (fc->queue_max - fc->queue_n);
-}
-
-/**
- * Get how many messages have we allowed to send to us from a direction.
- *
- * @param c Connection.
- * @param fwd Are we asking about traffic from FWD (BCK messages)?
- *
- * @return last_ack_sent - last_pid_recv
- */
-unsigned int
-GMC_get_allowed (struct CadetConnection *c, int fwd)
-{
- struct CadetFlowControl *fc;
-
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
- if (GM_is_pid_bigger(fc->last_pid_recv, fc->last_ack_sent))
- {
- return 0;
- }
- return (fc->last_ack_sent - fc->last_pid_recv);
-}
-
-/**
- * Get messages queued in a connection.
- *
- * @param c Connection.
- * @param fwd Is query about FWD traffic?
- *
- * @return Number of messages queued.
- */
-unsigned int
-GMC_get_qn (struct CadetConnection *c, int fwd)
-{
- struct CadetFlowControl *fc;
-
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
-
- return fc->queue_n;
-}
-
-
-/**
- * Get next PID to use.
- *
- * @param c Connection.
- * @param fwd Is query about FWD traffic?
- *
- * @return Last PID used + 1.
- */
-unsigned int
-GMC_get_pid (struct CadetConnection *c, int fwd)
-{
- struct CadetFlowControl *fc;
-
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
-
- return fc->last_pid_sent + 1;
-}
-
-
-/**
- * Allow the connection to advertise a buffer of the given size.
- *
- * The connection will send an @c fwd ACK message (so: in direction !fwd)
- * allowing up to last_pid_recv + buffer.
- *
- * @param c Connection.
- * @param buffer How many more messages the connection can accept.
- * @param fwd Is this about FWD traffic? (The ack will go dest->root).
- */
-void
-GMC_allow (struct CadetConnection *c, unsigned int buffer, int fwd)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " allowing %s %u messages %s\n",
- GMC_2s (c), buffer, GM_f2s (fwd));
- send_ack (c, buffer, fwd, GNUNET_NO);
-}
-
-
-/**
- * Notify other peers on a connection of a broken link. Mark connections
- * to destroy after all traffic has been sent.
- *
- * @param c Connection on which there has been a disconnection.
- * @param peer Peer that disconnected.
- */
-void
-GMC_notify_broken (struct CadetConnection *c,
- struct CadetPeer *peer)
-{
- int fwd;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " notify broken on %s due to %s disconnect\n",
- GMC_2s (c), GMP_2s (peer));
-
- fwd = peer == get_prev_hop (c);
-
- if (GNUNET_YES == GMC_is_terminal (c, fwd))
- {
- /* Local shutdown, no one to notify about this. */
- GMC_destroy (c);
- return;
- }
- if (GNUNET_NO == c->destroy)
- send_broken (c, &my_full_id, GMP_get_id (peer), fwd);
-
- /* Connection will have at least one pending message
- * (the one we just scheduled), so no point in checking whether to
- * destroy immediately. */
- c->destroy = GNUNET_YES;
- c->state = CADET_CONNECTION_DESTROYED;
-
- /**
- * Cancel all queues, if no message is left, connection will be destroyed.
- */
- connection_cancel_queues (c, !fwd);
-
- return;
-}
-
-
-/**
- * Is this peer the first one on the connection?
- *
- * @param c Connection.
- * @param fwd Is this about fwd traffic?
- *
- * @return #GNUNET_YES if origin, #GNUNET_NO if relay/terminal.
- */
-int
-GMC_is_origin (struct CadetConnection *c, int fwd)
-{
- if (!fwd && c->path->length - 1 == c->own_pos )
- return GNUNET_YES;
- if (fwd && 0 == c->own_pos)
- return GNUNET_YES;
- return GNUNET_NO;
-}
-
-
-/**
- * Is this peer the last one on the connection?
- *
- * @param c Connection.
- * @param fwd Is this about fwd traffic?
- * Note that the ROOT is the terminal for BCK traffic!
- *
- * @return #GNUNET_YES if terminal, #GNUNET_NO if relay/origin.
- */
-int
-GMC_is_terminal (struct CadetConnection *c, int fwd)
-{
- return GMC_is_origin (c, !fwd);
-}
-
-
-/**
- * See if we are allowed to send by the next hop in the given direction.
- *
- * @param c Connection.
- * @param fwd Is this about fwd traffic?
- *
- * @return #GNUNET_YES in case it's OK to send.
- */
-int
-GMC_is_sendable (struct CadetConnection *c, int fwd)
-{
- struct CadetFlowControl *fc;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " checking sendability of %s traffic on %s\n",
- GM_f2s (fwd), GMC_2s (c));
- if (NULL == c)
- {
- GNUNET_break (0);
- return GNUNET_YES;
- }
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " last ack recv: %u, last pid sent: %u\n",
- fc->last_ack_recv, fc->last_pid_sent);
- if (GM_is_pid_bigger (fc->last_ack_recv, fc->last_pid_sent))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " sendable\n");
- return GNUNET_YES;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " not sendable\n");
- return GNUNET_NO;
-}
-
-
-/**
- * Check if this connection is a direct one (never trim a direct connection).
- *
- * @param c Connection.
- *
- * @return #GNUNET_YES in case it's a direct connection, #GNUNET_NO otherwise.
- */
-int
-GMC_is_direct (struct CadetConnection *c)
-{
- return (c->path->length == 2) ? GNUNET_YES : GNUNET_NO;
-}
-
-/**
- * Sends an already built message on a connection, properly registering
- * all used resources.
- *
- * @param message Message to send. Function makes a copy of it.
- * If message is not hop-by-hop, decrements TTL of copy.
- * @param payload_type Type of payload, in case the message is encrypted.
- * @param c Connection on which this message is transmitted.
- * @param fwd Is this a fwd message?
- * @param force Force the connection to accept the message (buffer overfill).
- * @param cont Continuation called once message is sent. Can be NULL.
- * @param cont_cls Closure for @c cont.
- *
- * @return Handle to cancel the message before it's sent.
- * NULL on error or if @c cont is NULL.
- * Invalid on @c cont call.
- */
-struct CadetConnectionQueue *
-GMC_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
- uint16_t payload_type, uint32_t payload_id,
- struct CadetConnection *c, int fwd, int force,
- GMC_sent cont, void *cont_cls)
-{
- struct CadetFlowControl *fc;
- struct CadetConnectionQueue *q;
- void *data;
- size_t size;
- uint16_t type;
- int droppable;
-
- size = ntohs (message->size);
- data = GNUNET_malloc (size);
- memcpy (data, message, size);
- type = ntohs (message->type);
- LOG (GNUNET_ERROR_TYPE_INFO, "--> %s (%s %u) on connection %s (%u bytes)\n",
- GM_m2s (type), GM_m2s (payload_type), payload_id, GMC_2s (c), size);
-
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
- droppable = GNUNET_NO == force;
- switch (type)
- {
- struct GNUNET_CADET_Encrypted *emsg;
- struct GNUNET_CADET_KX *kmsg;
- struct GNUNET_CADET_ACK *amsg;
- struct GNUNET_CADET_Poll *pmsg;
- struct GNUNET_CADET_ConnectionDestroy *dmsg;
- struct GNUNET_CADET_ConnectionBroken *bmsg;
- uint32_t ttl;
-
- case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
- emsg = (struct GNUNET_CADET_Encrypted *) data;
- ttl = ntohl (emsg->ttl);
- if (0 == ttl)
- {
- GNUNET_break_op (0);
- GNUNET_free (data);
- return NULL;
- }
- emsg->cid = c->id;
- emsg->ttl = htonl (ttl - 1);
- emsg->pid = htonl (0);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Q_N+ %p %u\n", fc, fc->queue_n);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "last pid sent %u\n", fc->last_pid_sent);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " ack recv %u\n", fc->last_ack_recv);
- if (GNUNET_YES == droppable)
- {
- fc->queue_n++;
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " not droppable, Q_N stays the same\n");
- }
- if (GM_is_pid_bigger (fc->last_pid_sent + 1, fc->last_ack_recv))
- {
- GMC_start_poll (c, fwd);
- }
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_KX:
- kmsg = (struct GNUNET_CADET_KX *) data;
- kmsg->cid = c->id;
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_ACK:
- amsg = (struct GNUNET_CADET_ACK *) data;
- amsg->cid = c->id;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " ack %u\n", ntohl (amsg->ack));
- droppable = GNUNET_NO;
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_POLL:
- pmsg = (struct GNUNET_CADET_Poll *) data;
- pmsg->cid = c->id;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " poll %u\n", ntohl (pmsg->pid));
- droppable = GNUNET_NO;
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
- dmsg = (struct GNUNET_CADET_ConnectionDestroy *) data;
- dmsg->cid = c->id;
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
- bmsg = (struct GNUNET_CADET_ConnectionBroken *) data;
- bmsg->cid = c->id;
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE:
- GNUNET_break (0);
- /* falltrough */
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK:
- break;
-
- default:
- GNUNET_break (0);
- GNUNET_free (data);
- return NULL;
- }
-
- if (fc->queue_n > fc->queue_max && droppable)
- {
- GNUNET_STATISTICS_update (stats, "# messages dropped (buffer full)",
- 1, GNUNET_NO);
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "queue full: %u/%u\n",
- fc->queue_n, fc->queue_max);
- if (GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED == type)
- {
- fc->queue_n--;
- }
- GNUNET_free (data);
- return NULL; /* Drop this message */
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %p %u\n", c, c->pending_messages);
-// c->pending_messages++;
-
- q = GNUNET_new (struct CadetConnectionQueue);
- q->forced = !droppable;
- q->q = GMP_queue_add (get_hop (c, fwd), data, type, payload_type, payload_id,
- size, c, fwd, &conn_message_sent, q);
- if (NULL == q->q)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING dropping msg on %s\n", GMC_2s (c));
- GNUNET_free (data);
- GNUNET_free (q);
- return NULL;
- }
- q->cont = cont;
- q->cont_cls = cont_cls;
- return (NULL == cont) ? NULL : q;
-}
-
-
-/**
- * Cancel a previously sent message while it's in the queue.
- *
- * ONLY can be called before the continuation given to the send function
- * is called. Once the continuation is called, the message is no longer in the
- * queue.
- *
- * @param q Handle to the queue.
- */
-void
-GMC_cancel (struct CadetConnectionQueue *q)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "! GMC cancel message\n");
-
- /* queue destroy calls message_sent, which calls q->cont and frees q */
- GMP_queue_destroy (q->q, GNUNET_YES, GNUNET_NO, 0);
-}
-
-
-/**
- * Sends a CREATE CONNECTION message for a path to a peer.
- * Changes the connection and tunnel states if necessary.
- *
- * @param connection Connection to create.
- */
-void
-GMC_send_create (struct CadetConnection *connection)
-{
- enum CadetTunnel3CState state;
- size_t size;
-
- size = sizeof (struct GNUNET_CADET_ConnectionCreate);
- size += connection->path->length * sizeof (struct GNUNET_PeerIdentity);
-
- LOG (GNUNET_ERROR_TYPE_INFO, "===> %s on connection %s (%u bytes)\n",
- GM_m2s (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE),
- GMC_2s (connection), size);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %p %u (create)\n",
- connection, connection->pending_messages);
- connection->pending_messages++;
-
- connection->maintenance_q =
- GMP_queue_add (get_next_hop (connection), NULL,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, 0,
- size, connection, GNUNET_YES, &conn_message_sent, NULL);
-
- state = GMT_get_cstate (connection->t);
- if (CADET_TUNNEL3_SEARCHING == state || CADET_TUNNEL3_NEW == state)
- GMT_change_cstate (connection->t, CADET_TUNNEL3_WAITING);
- if (CADET_CONNECTION_NEW == connection->state)
- connection_change_state (connection, CADET_CONNECTION_SENT);
-}
-
-
-/**
- * Send a message to all peers in this connection that the connection
- * is no longer valid.
- *
- * If some peer should not receive the message, it should be zero'ed out
- * before calling this function.
- *
- * @param c The connection whose peers to notify.
- */
-void
-GMC_send_destroy (struct CadetConnection *c)
-{
- struct GNUNET_CADET_ConnectionDestroy msg;
-
- if (GNUNET_YES == c->destroy)
- return;
-
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);;
- msg.cid = c->id;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " sending connection destroy for connection %s\n",
- GMC_2s (c));
-
- if (GNUNET_NO == GMC_is_terminal (c, GNUNET_YES))
- GMC_send_prebuilt_message (&msg.header,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY, 0,
- c, GNUNET_YES, GNUNET_YES, NULL, NULL);
- if (GNUNET_NO == GMC_is_terminal (c, GNUNET_NO))
- GMC_send_prebuilt_message (&msg.header,
- GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY, 0,
- c, GNUNET_NO, GNUNET_YES, NULL, NULL);
- c->destroy = GNUNET_YES;
- c->state = CADET_CONNECTION_DESTROYED;
-}
-
-
-/**
- * @brief Start a polling timer for the connection.
- *
- * When a neighbor does not accept more traffic on the connection it could be
- * caused by a simple congestion or by a lost ACK. Polling enables to check
- * for the lastest ACK status for a connection.
- *
- * @param c Connection.
- * @param fwd Should we poll in the FWD direction?
- */
-void
-GMC_start_poll (struct CadetConnection *c, int fwd)
-{
- struct CadetFlowControl *fc;
-
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL %s requested\n",
- GM_f2s (fwd));
- if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task || NULL != fc->poll_msg)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " *** not needed (%u, %p)\n",
- fc->poll_task, fc->poll_msg);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL started on request\n");
- fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time,
- &connection_poll,
- fc);
-}
-
-
-/**
- * @brief Stop polling a connection for ACKs.
- *
- * Once we have enough ACKs for future traffic, polls are no longer necessary.
- *
- * @param c Connection.
- * @param fwd Should we stop the poll in the FWD direction?
- */
-void
-GMC_stop_poll (struct CadetConnection *c, int fwd)
-{
- struct CadetFlowControl *fc;
-
- fc = fwd ? &c->fwd_fc : &c->bck_fc;
- if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task)
- {
- GNUNET_SCHEDULER_cancel (fc->poll_task);
- fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
- }
-}
-
-/**
- * Get a (static) string for a connection.
- *
- * @param c Connection.
- */
-const char *
-GMC_2s (const struct CadetConnection *c)
-{
- if (NULL == c)
- return "NULL";
-
- if (NULL != c->t)
- {
- static char buf[128];
-
- sprintf (buf, "%s (->%s)",
- GNUNET_h2s (GM_h2hc (GMC_get_id (c))), GMT_2s (c->t));
- return buf;
- }
- return GNUNET_h2s (GM_h2hc (&c->id));
-}
Deleted: gnunet/src/mesh/gnunet-service-cadet_connection.h
===================================================================
--- gnunet/src/mesh/gnunet-service-cadet_connection.h 2014-05-07 12:07:02 UTC
(rev 33185)
+++ gnunet/src/mesh/gnunet-service-cadet_connection.h 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -1,566 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2013 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_connection.h
- * @brief cadet service; dealing with connections
- * @author Bartlomiej Polot
- *
- * All functions in this file should use the prefix GMC (Gnunet Cadet
Connection)
- */
-
-#ifndef GNUNET_SERVICE_CADET_CONNECTION_H
-#define GNUNET_SERVICE_CADET_CONNECTION_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0 /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "gnunet_util_lib.h"
-
-
-/**
- * All the states a connection can be in.
- */
-enum CadetConnectionState
-{
- /**
- * Uninitialized status, should never appear in operation.
- */
- CADET_CONNECTION_NEW,
-
- /**
- * Connection create message sent, waiting for ACK.
- */
- CADET_CONNECTION_SENT,
-
- /**
- * Connection ACK sent, waiting for ACK.
- */
- CADET_CONNECTION_ACK,
-
- /**
- * Connection confirmed, ready to carry traffic.
- */
- CADET_CONNECTION_READY,
-
- /**
- * Connection to be destroyed, just waiting to empty queues.
- */
- CADET_CONNECTION_DESTROYED,
-};
-
-
-/**
- * Struct containing all information regarding a connection to a peer.
- */
-struct CadetConnection;
-
-/**
- * Handle for messages queued but not yet sent.
- */
-struct CadetConnectionQueue;
-
-#include "cadet_path.h"
-#include "gnunet-service-cadet_channel.h"
-#include "gnunet-service-cadet_peer.h"
-
-
-
-/**
- * Callback called when a queued message is sent.
- *
- * @param cls Closure.
- * @param c Connection this message was on.
- * @param type Type of message sent.
- * @param fwd Was this a FWD going message?
- * @param size Size of the message.
- */
-typedef void (*GMC_sent) (void *cls,
- struct CadetConnection *c,
- struct CadetConnectionQueue *q,
- uint16_t type, int fwd, size_t size);
-
-/**
- * Core handler for connection creation.
- *
- * @param cls Closure (unused).
- * @param peer Sender (neighbor).
- * @param message Message.
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-GMC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message);
-
-/**
- * Core handler for path confirmations.
- *
- * @param cls closure
- * @param message message
- * @param peer peer identity this notification is about
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-GMC_handle_confirm (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message);
-
-/**
- * Core handler for notifications of broken paths
- *
- * @param cls Closure (unused).
- * @param id Peer identity of sending neighbor.
- * @param message Message.
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-GMC_handle_broken (void* cls,
- const struct GNUNET_PeerIdentity* id,
- const struct GNUNET_MessageHeader* message);
-
-/**
- * Core handler for tunnel destruction
- *
- * @param cls Closure (unused).
- * @param peer Peer identity of sending neighbor.
- * @param message Message.
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-GMC_handle_destroy (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message);
-
-/**
- * Core handler for encrypted cadet network traffic (channel mgmt, data).
- *
- * @param cls Closure (unused).
- * @param message Message received.
- * @param peer Peer who sent the message.
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-GMC_handle_encrypted (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message);
-
-/**
- * Core handler for key exchange traffic (ephemeral key, ping, pong).
- *
- * @param cls Closure (unused).
- * @param message Message received.
- * @param peer Peer who sent the message.
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-GMC_handle_kx (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message);
-
-/**
- * Core handler for cadet network traffic point-to-point acks.
- *
- * @param cls closure
- * @param message message
- * @param peer peer identity this notification is about
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-GMC_handle_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message);
-
-/**
- * Core handler for cadet network traffic point-to-point ack polls.
- *
- * @param cls closure
- * @param message message
- * @param peer peer identity this notification is about
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-GMC_handle_poll (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message);
-
-/**
- * Core handler for cadet keepalives.
- *
- * @param cls closure
- * @param message message
- * @param peer peer identity this notification is about
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- *
- * TODO: Check who we got this from, to validate route.
- */
-int
-GMC_handle_keepalive (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message);
-
-/**
- * Send an ACK on the appropriate connection/channel, depending on
- * the direction and the position of the peer.
- *
- * @param c Which connection to send the hop-by-hop ACK.
- * @param fwd Is this a fwd ACK? (will go dest->root).
- * @param force Send the ACK even if suboptimal (e.g. requested by POLL).
- */
-void
-GMC_send_ack (struct CadetConnection *c, int fwd, int force);
-
-/**
- * Initialize the connections subsystem
- *
- * @param c Configuration handle.
- */
-void
-GMC_init (const struct GNUNET_CONFIGURATION_Handle *c);
-
-/**
- * Shut down the connections subsystem.
- */
-void
-GMC_shutdown (void);
-
-/**
- * Create a connection.
- *
- * @param cid Connection ID (either created locally or imposed remotely).
- * @param t Tunnel this connection belongs to (or NULL);
- * @param p Path this connection has to use.
- * @param own_pos Own position in the @c p path.
- *
- * @return Newly created connection, NULL in case of error (own id not in
path).
- */
-struct CadetConnection *
-GMC_new (const struct GNUNET_CADET_Hash *cid,
- struct CadetTunnel3 *t,
- struct CadetPeerPath *p,
- unsigned int own_pos);
-
-/**
- * Connection is no longer needed: destroy it.
- *
- * Cancels all pending traffic (including possible DESTROY messages), all
- * maintenance tasks and removes the connection from neighbor peers and tunnel.
- *
- * @param c Connection to destroy.
- */
-void
-GMC_destroy (struct CadetConnection *c);
-
-/**
- * Get the connection ID.
- *
- * @param c Connection to get the ID from.
- *
- * @return ID of the connection.
- */
-const struct GNUNET_CADET_Hash *
-GMC_get_id (const struct CadetConnection *c);
-
-
-/**
- * Get a hash for the connection ID.
- *
- * @param c Connection to get the hash.
- *
- * @return Hash expanded from the ID of the connection.
- */
-const struct GNUNET_HashCode *
-GMC_get_h (const struct CadetConnection *c);
-
-
-/**
- * Get the connection path.
- *
- * @param c Connection to get the path from.
- *
- * @return path used by the connection.
- */
-const struct CadetPeerPath *
-GMC_get_path (const struct CadetConnection *c);
-
-/**
- * Get the connection state.
- *
- * @param c Connection to get the state from.
- *
- * @return state of the connection.
- */
-enum CadetConnectionState
-GMC_get_state (const struct CadetConnection *c);
-
-/**
- * Get the connection tunnel.
- *
- * @param c Connection to get the tunnel from.
- *
- * @return tunnel of the connection.
- */
-struct CadetTunnel3 *
-GMC_get_tunnel (const struct CadetConnection *c);
-
-/**
- * Get free buffer space in a connection.
- *
- * @param c Connection.
- * @param fwd Is query about FWD traffic?
- *
- * @return Free buffer space [0 - max_msgs_queue/max_connections]
- */
-unsigned int
-GMC_get_buffer (struct CadetConnection *c, int fwd);
-
-/**
- * Get how many messages have we allowed to send to us from a direction.
- *
- * @param c Connection.
- * @param fwd Are we asking about traffic from FWD (BCK messages)?
- *
- * @return last_ack_sent - last_pid_recv
- */
-unsigned int
-GMC_get_allowed (struct CadetConnection *c, int fwd);
-
-/**
- * Get messages queued in a connection.
- *
- * @param c Connection.
- * @param fwd Is query about FWD traffic?
- *
- * @return Number of messages queued.
- */
-unsigned int
-GMC_get_qn (struct CadetConnection *c, int fwd);
-
-/**
- * Get next PID to use.
- *
- * @param c Connection.
- * @param fwd Is query about FWD traffic?
- *
- * @return Last PID used + 1.
- */
-unsigned int
-GMC_get_pid (struct CadetConnection *c, int fwd);
-
-/**
- * Allow the connection to advertise a buffer of the given size.
- *
- * The connection will send an @c fwd ACK message (so: in direction !fwd)
- * allowing up to last_pid_recv + buffer.
- *
- * @param c Connection.
- * @param buffer How many more messages the connection can accept.
- * @param fwd Is this about FWD traffic? (The ack will go dest->root).
- */
-void
-GMC_allow (struct CadetConnection *c, unsigned int buffer, int fwd);
-
-/**
- * Send FWD keepalive packets for a connection.
- *
- * @param cls Closure (connection for which to send the keepalive).
- * @param tc Notification context.
- */
-void
-GMC_fwd_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
-
-/**
- * Send BCK keepalive packets for a connection.
- *
- * @param cls Closure (connection for which to send the keepalive).
- * @param tc Notification context.
- */
-void
-GMC_bck_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
-
-
-/**
- * Notify other peers on a connection of a broken link. Mark connections
- * to destroy after all traffic has been sent.
- *
- * @param c Connection on which there has been a disconnection.
- * @param peer Peer that disconnected.
- */
-void
-GMC_notify_broken (struct CadetConnection *c,
- struct CadetPeer *peer);
-
-/**
- * Is this peer the first one on the connection?
- *
- * @param c Connection.
- * @param fwd Is this about fwd traffic?
- *
- * @return #GNUNET_YES if origin, #GNUNET_NO if relay/terminal.
- */
-int
-GMC_is_origin (struct CadetConnection *c, int fwd);
-
-/**
- * Is this peer the last one on the connection?
- *
- * @param c Connection.
- * @param fwd Is this about fwd traffic?
- * Note that the ROOT is the terminal for BCK traffic!
- *
- * @return #GNUNET_YES if terminal, #GNUNET_NO if relay/origin.
- */
-int
-GMC_is_terminal (struct CadetConnection *c, int fwd);
-
-/**
- * See if we are allowed to send by the next hop in the given direction.
- *
- * @param c Connection.
- * @param fwd Is this about fwd traffic?
- *
- * @return #GNUNET_YES in case it's OK to send.
- */
-int
-GMC_is_sendable (struct CadetConnection *c, int fwd);
-
-/**
- * Check if this connection is a direct one (never trim a direct connection).
- *
- * @param c Connection.
- *
- * @return #GNUNET_YES in case it's a direct connection, #GNUNET_NO otherwise.
- */
-int
-GMC_is_direct (struct CadetConnection *c);
-
-/**
- * Cancel a previously sent message while it's in the queue.
- *
- * ONLY can be called before the continuation given to the send function
- * is called. Once the continuation is called, the message is no longer in the
- * queue.
- *
- * @param q Handle to the queue.
- */
-void
-GMC_cancel (struct CadetConnectionQueue *q);
-
-/**
- * Sends an already built message on a connection, properly registering
- * all used resources.
- *
- * @param message Message to send. Function makes a copy of it.
- * If message is not hop-by-hop, decrements TTL of copy.
- * @param payload_type Type of payload, in case the message is encrypted.
- * @param c Connection on which this message is transmitted.
- * @param fwd Is this a fwd message?
- * @param force Force the connection to accept the message (buffer overfill).
- * @param cont Continuation called once message is sent. Can be NULL.
- * @param cont_cls Closure for @c cont.
- *
- * @return Handle to cancel the message before it's sent.
- * NULL on error or if @c cont is NULL.
- * Invalid on @c cont call.
- */
-struct CadetConnectionQueue *
-GMC_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
- uint16_t payload_type, uint32_t payload_id,
- struct CadetConnection *c, int fwd, int force,
- GMC_sent cont, void *cont_cls);
-
-/**
- * Sends a CREATE CONNECTION message for a path to a peer.
- * Changes the connection and tunnel states if necessary.
- *
- * @param connection Connection to create.
- */
-void
-GMC_send_create (struct CadetConnection *connection);
-
-/**
- * Send a message to all peers in this connection that the connection
- * is no longer valid.
- *
- * If some peer should not receive the message, it should be zero'ed out
- * before calling this function.
- *
- * @param c The connection whose peers to notify.
- */
-void
-GMC_send_destroy (struct CadetConnection *c);
-
-/**
- * @brief Start a polling timer for the connection.
- *
- * When a neighbor does not accept more traffic on the connection it could be
- * caused by a simple congestion or by a lost ACK. Polling enables to check
- * for the lastest ACK status for a connection.
- *
- * @param c Connection.
- * @param fwd Should we poll in the FWD direction?
- */
-void
-GMC_start_poll (struct CadetConnection *c, int fwd);
-
-
-/**
- * @brief Stop polling a connection for ACKs.
- *
- * Once we have enough ACKs for future traffic, polls are no longer necessary.
- *
- * @param c Connection.
- * @param fwd Should we stop the poll in the FWD direction?
- */
-void
-GMC_stop_poll (struct CadetConnection *c, int fwd);
-
-/**
- * Get a (static) string for a connection.
- *
- * @param c Connection.
- */
-const char *
-GMC_2s (const struct CadetConnection *c);
-
-#if 0 /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_SERVICE_CADET_CONNECTION_H */
-#endif
-/* end of gnunet-service-cadet_connection.h */
Deleted: gnunet/src/mesh/gnunet-service-cadet_dht.c
===================================================================
--- gnunet/src/mesh/gnunet-service-cadet_dht.c 2014-05-07 12:07:02 UTC (rev
33185)
+++ gnunet/src/mesh/gnunet-service-cadet_dht.c 2014-05-07 12:07:16 UTC (rev
33186)
@@ -1,423 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2013 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#include "gnunet_dht_service.h"
-#include "gnunet_statistics_service.h"
-
-#include "cadet_path.h"
-#include "gnunet-service-cadet_dht.h"
-#include "gnunet-service-cadet_peer.h"
-#include "gnunet-service-cadet_hello.h"
-
-#define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__)
-
-
-/******************************************************************************/
-/******************************** STRUCTS
**********************************/
-/******************************************************************************/
-
-/**
- * Handle for DHT searches.
- */
-struct GMD_search_handle
-{
- /** DHT_GET handle. */
- struct GNUNET_DHT_GetHandle *dhtget;
-
- /** Provided callback to call when a path is found. */
- GMD_search_callback callback;
-
- /** Provided closure. */
- void *cls;
-
- /** Peer ID searched for */
- GNUNET_PEER_Id peer_id;
-};
-
-
-/******************************************************************************/
-/******************************* GLOBALS
***********************************/
-/******************************************************************************/
-
-/**
- * Global handle to the statistics service.
- */
-extern struct GNUNET_STATISTICS_Handle *stats;
-
-/**
- * Own ID (short value).
- */
-extern GNUNET_PEER_Id myid;
-
-/**
- * Own ID (full value).
- */
-extern struct GNUNET_PeerIdentity my_full_id;
-
-/**
- * Handle to use DHT.
- */
-static struct GNUNET_DHT_Handle *dht_handle;
-
-/**
- * How often to PUT own ID in the DHT.
- */
-static struct GNUNET_TIME_Relative id_announce_time;
-
-/**
- * DHT replication level, see DHT API: GNUNET_DHT_get_start, GNUNET_DHT_put.
- */
-static unsigned long long dht_replication_level;
-
-/**
- * Task to periodically announce itself in the network.
- */
-static GNUNET_SCHEDULER_TaskIdentifier announce_id_task;
-
-/**
- * GET requests to stop on shutdown.
- */
-static struct GNUNET_CONTAINER_MultiHashMap32 *get_requests;
-
-/******************************************************************************/
-/******************************** STATIC
***********************************/
-/******************************************************************************/
-
-
-/**
- * Build a PeerPath from the paths returned from the DHT, reversing the paths
- * to obtain a local peer -> destination path and interning the peer ids.
- *
- * @return Newly allocated and created path
- *
- * FIXME refactor and use build_path_from_peer_ids
- */
-static struct CadetPeerPath *
-path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
- unsigned int get_path_length,
- const struct GNUNET_PeerIdentity *put_path,
- unsigned int put_path_length)
-{
- struct CadetPeerPath *p;
- GNUNET_PEER_Id id;
- int i;
-
- p = path_new (1);
- p->peers[0] = myid;
- GNUNET_PEER_change_rc (myid, 1);
- i = get_path_length;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " GET has %d hops.\n", i);
- for (i--; i >= 0; i--)
- {
- id = GNUNET_PEER_intern (&get_path[i]);
- if (p->length > 0 && id == p->peers[p->length - 1])
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n");
- GNUNET_PEER_change_rc (id, -1);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Adding from GET: %s.\n",
- GNUNET_i2s (&get_path[i]));
- p->length++;
- p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) *
p->length);
- p->peers[p->length - 1] = id;
- }
- }
- i = put_path_length;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " PUT has %d hops.\n", i);
- for (i--; i >= 0; i--)
- {
- id = GNUNET_PEER_intern (&put_path[i]);
- if (id == myid)
- {
- /* PUT path went through us, so discard the path up until now and start
- * from here to get a much shorter (and loop-free) path.
- */
- path_destroy (p);
- p = path_new (0);
- }
- if (p->length > 0 && id == p->peers[p->length - 1])
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n");
- GNUNET_PEER_change_rc (id, -1);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Adding from PUT: %s.\n",
- GNUNET_i2s (&put_path[i]));
- p->length++;
- p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) *
p->length);
- p->peers[p->length - 1] = id;
- }
- }
-#if CADET_DEBUG
- if (get_path_length > 0)
- LOG (GNUNET_ERROR_TYPE_DEBUG, " (first of GET: %s)\n",
- GNUNET_i2s (&get_path[0]));
- if (put_path_length > 0)
- LOG (GNUNET_ERROR_TYPE_DEBUG, " (first of PUT: %s)\n",
- GNUNET_i2s (&put_path[0]));
- LOG (GNUNET_ERROR_TYPE_DEBUG, " In total: %d hops\n",
- p->length);
- for (i = 0; i < p->length; i++)
- {
- struct GNUNET_PeerIdentity peer_id;
-
- GNUNET_PEER_resolve (p->peers[i], &peer_id);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " %u: %s\n", p->peers[i],
- GNUNET_i2s (&peer_id));
- }
-#endif
- return p;
-}
-
-
-/**
- * Function to process paths received for a new peer addition. The recorded
- * paths form the initial tunnel, which can be optimized later.
- * Called on each result obtained for the DHT search.
- *
- * @param cls closure
- * @param exp when will this value expire
- * @param key key of the result
- * @param get_path path of the get request
- * @param get_path_length lenght of get_path
- * @param put_path path of the put request
- * @param put_path_length length of the put_path
- * @param type type of the result
- * @param size number of bytes in data
- * @param data pointer to the result data
- */
-static void
-dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
- const struct GNUNET_HashCode * key,
- const struct GNUNET_PeerIdentity *get_path,
- unsigned int get_path_length,
- const struct GNUNET_PeerIdentity *put_path,
- unsigned int put_path_length, enum GNUNET_BLOCK_Type type,
- size_t size, const void *data)
-{
- struct GMD_search_handle *h = cls;
- struct GNUNET_HELLO_Message *hello;
- struct CadetPeerPath *p;
- struct CadetPeer *peer;
- char *s;
-
- p = path_build_from_dht (get_path, get_path_length,
- put_path, put_path_length);
- s = path_2s (p);
- LOG (GNUNET_ERROR_TYPE_INFO, "Got path from DHT: %s\n", s);
- GNUNET_free_non_null (s);
- peer = GMP_get_short (p->peers[p->length - 1]);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Got HELLO for %s\n", GMP_2s (peer));
- h->callback (h->cls, p);
- path_destroy (p);
- hello = (struct GNUNET_HELLO_Message *) data;
- GMP_set_hello (peer, hello);
- GMP_try_connect (peer);
- return;
-}
-
-
-/**
- * Periodically announce self id in the DHT
- *
- * @param cls closure
- * @param tc task context
- */
-static void
-announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct GNUNET_HashCode phash;
- const struct GNUNET_HELLO_Message *hello;
- size_t size;
- struct GNUNET_TIME_Absolute expiration;
- struct GNUNET_TIME_Relative retry_time;
-
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- {
- announce_id_task = GNUNET_SCHEDULER_NO_TASK;
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Announce ID\n");
-
- /* TODO
- * - Set data expiration in function of X
- * - Adapt X to churn
- */
- hello = GMH_get_mine ();
- if (NULL == hello || (size = GNUNET_HELLO_size (hello)) == 0)
- {
- /* Peerinfo gave us no hello yet, try again in a second. */
- announce_id_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
- &announce_id, cls);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " no hello, waiting!\n");
- return;
- }
- expiration = GNUNET_HELLO_get_last_expiration (hello);
- retry_time = GNUNET_TIME_absolute_get_remaining (expiration);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Hello %p size: %u\n", hello, size);
- memset (&phash, 0, sizeof (phash));
- memcpy (&phash, &my_full_id, sizeof (my_full_id));
- GNUNET_DHT_put (dht_handle, /* DHT handle */
- &phash, /* Key to use */
- dht_replication_level, /* Replication level */
- GNUNET_DHT_RO_RECORD_ROUTE
- | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */
- GNUNET_BLOCK_TYPE_DHT_HELLO, /* Block type */
- size, /* Size of the data */
- (const char *) hello, /* Data itself */
- expiration, /* Data expiration */
- retry_time, /* Retry time */
- NULL, /* Continuation */
- NULL); /* Continuation closure */
- announce_id_task =
- GNUNET_SCHEDULER_add_delayed (id_announce_time, &announce_id, cls);
-}
-
-/**
- * Iterator over hash map entries and stop GET requests before disconnecting
- * from the DHT.
- *
- * @param cls Closure (unused)
- * @param key Current peer ID.
- * @param value Value in the hash map (GMD_search_handle).
- *
- * @return #GNUNET_YES, we should continue to iterate,
- */
-int
-stop_get (void *cls,
- uint32_t key,
- void *value)
-{
- struct GMD_search_handle *h = value;
-
- GMD_search_stop (h);
- return GNUNET_YES;
-}
-
-
-/******************************************************************************/
-/******************************** API
***********************************/
-/******************************************************************************/
-
-/**
- * Initialize the DHT subsystem.
- *
- * @param c Configuration.
- */
-void
-GMD_init (const struct GNUNET_CONFIGURATION_Handle *c)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (c, "CADET",
"DHT_REPLICATION_LEVEL",
- &dht_replication_level))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
- "CADET", "DHT_REPLICATION_LEVEL", "USING
DEFAULT");
- dht_replication_level = 3;
- }
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (c, "CADET", "ID_ANNOUNCE_TIME",
- &id_announce_time))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "CADET", "ID_ANNOUNCE_TIME", "MISSING");
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
-
- dht_handle = GNUNET_DHT_connect (c, 64);
- if (NULL == dht_handle)
- {
- GNUNET_break (0);
- }
-
- announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL);
- get_requests = GNUNET_CONTAINER_multihashmap32_create (32);
-}
-
-
-/**
- * Shut down the DHT subsystem.
- */
-void
-GMD_shutdown (void)
-{
- GNUNET_CONTAINER_multihashmap32_iterate (get_requests, &stop_get, NULL);
- GNUNET_CONTAINER_multihashmap32_destroy (get_requests);
- if (dht_handle != NULL)
- {
- GNUNET_DHT_disconnect (dht_handle);
- dht_handle = NULL;
- }
- if (GNUNET_SCHEDULER_NO_TASK != announce_id_task)
- {
- GNUNET_SCHEDULER_cancel (announce_id_task);
- announce_id_task = GNUNET_SCHEDULER_NO_TASK;
- }
-}
-
-struct GMD_search_handle *
-GMD_search (const struct GNUNET_PeerIdentity *peer_id,
- GMD_search_callback callback, void *cls)
-{
- struct GNUNET_HashCode phash;
- struct GMD_search_handle *h;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " Starting DHT GET for peer %s\n", GNUNET_i2s (peer_id));
- memset (&phash, 0, sizeof (phash));
- memcpy (&phash, peer_id, sizeof (*peer_id));
- h = GNUNET_new (struct GMD_search_handle);
- h->peer_id = GNUNET_PEER_intern (peer_id);
- h->callback = callback;
- h->cls = cls;
- h->dhtget = GNUNET_DHT_get_start (dht_handle, /* handle */
- GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */
- &phash, /* key to search */
- dht_replication_level, /* replication
level */
- GNUNET_DHT_RO_RECORD_ROUTE |
- GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
- NULL, /* xquery */
- 0, /* xquery bits */
- &dht_get_id_handler, h);
- GNUNET_CONTAINER_multihashmap32_put (get_requests, h->peer_id, h,
-
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
- return h;
-}
-
-void
-GMD_search_stop (struct GMD_search_handle *h)
-{
- GNUNET_break (GNUNET_OK ==
- GNUNET_CONTAINER_multihashmap32_remove (get_requests,
- h->peer_id, h));
- GNUNET_DHT_get_stop (h->dhtget);
- GNUNET_free (h);
-}
Deleted: gnunet/src/mesh/gnunet-service-cadet_dht.h
===================================================================
--- gnunet/src/mesh/gnunet-service-cadet_dht.h 2014-05-07 12:07:02 UTC (rev
33185)
+++ gnunet/src/mesh/gnunet-service-cadet_dht.h 2014-05-07 12:07:16 UTC (rev
33186)
@@ -1,92 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2013 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_dht.h
- * @brief cadet service; dealing with DHT requests and results
- * @author Bartlomiej Polot
- *
- * All functions in this file should use the prefix GMD (Gnunet Cadet Dht)
- */
-
-#ifndef GNUNET_SERVICE_CADET_DHT_H
-#define GNUNET_SERVICE_CADET_DHT_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0 /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-struct GMD_search_handle;
-
-
-/**
- * Callback called on each path found over the DHT.
- *
- * @param cls Closure.
- * @param path An unchecked, unoptimized path to the target node.
- * After callback will no longer be valid!
- */
-typedef void (*GMD_search_callback) (void *cls,
- const struct CadetPeerPath *path);
-
-/******************************************************************************/
-/******************************** API
***********************************/
-/******************************************************************************/
-
-/**
- * Initialize the DHT subsystem.
- *
- * @param c Configuration.
- */
-void
-GMD_init (const struct GNUNET_CONFIGURATION_Handle *c);
-
-/**
- * Shut down the DHT subsystem.
- */
-void
-GMD_shutdown (void);
-
-
-struct GMD_search_handle *
-GMD_search (const struct GNUNET_PeerIdentity *peer_id,
- GMD_search_callback callback, void *cls);
-
-
-void
-GMD_search_stop (struct GMD_search_handle *h);
-
-#if 0 /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_CADET_SERVICE_LOCAL_H */
-#endif
-/* end of gnunet-cadet-service_LOCAL.h */
\ No newline at end of file
Deleted: gnunet/src/mesh/gnunet-service-cadet_hello.c
===================================================================
--- gnunet/src/mesh/gnunet-service-cadet_hello.c 2014-05-07 12:07:02 UTC
(rev 33185)
+++ gnunet/src/mesh/gnunet-service-cadet_hello.c 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -1,198 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2014 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#include "gnunet_statistics_service.h"
-#include "gnunet_peerinfo_service.h"
-
-#include "cadet_protocol.h"
-#include "cadet_path.h"
-
-#include "gnunet-service-cadet_hello.h"
-#include "gnunet-service-cadet_peer.h"
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-hll",__VA_ARGS__)
-
-
-/******************************************************************************/
-/******************************** STRUCTS
**********************************/
-/******************************************************************************/
-
-
-
-/******************************************************************************/
-/******************************* GLOBALS
***********************************/
-/******************************************************************************/
-
-/**
- * Global handle to the statistics service.
- */
-extern struct GNUNET_STATISTICS_Handle *stats;
-
-/**
- * Local peer own ID (memory efficient handle).
- */
-extern GNUNET_PEER_Id myid;
-
-/**
- * Local peer own ID (full value).
- */
-extern struct GNUNET_PeerIdentity my_full_id;
-
-
-/**
- * Don't try to recover tunnels if shutting down.
- */
-extern int shutting_down;
-
-
-/**
- * Hello message of local peer.
- */
-const struct GNUNET_HELLO_Message *mine;
-
-/**
- * Handle to peerinfo service.
- */
-static struct GNUNET_PEERINFO_Handle *peerinfo;
-
-/**
- * Iterator context.
- */
-struct GNUNET_PEERINFO_NotifyContext* nc;
-
-
-/******************************************************************************/
-/******************************** STATIC
***********************************/
-/******************************************************************************/
-
-/**
- * Process each hello message received from peerinfo.
- *
- * @param cls Closure (unused).
- * @param peer Identity of the peer.
- * @param hello Hello of the peer.
- * @param err_msg Error message.
- */
-static void
-got_hello (void *cls, const struct GNUNET_PeerIdentity *id,
- const struct GNUNET_HELLO_Message *hello,
- const char *err_msg)
-{
- struct CadetPeer *peer;
-
- if (NULL == id || NULL == hello)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " hello with id %p and msg %p\n", id, hello);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " hello for %s (%d bytes), expires on %s\n",
- GNUNET_i2s (id), GNUNET_HELLO_size (hello),
- GNUNET_STRINGS_absolute_time_to_string
(GNUNET_HELLO_get_last_expiration(hello)));
- peer = GMP_get (id);
- GMP_set_hello (peer, hello);
-
- if (GMP_get_short_id (peer) == myid)
- {
- mine = GMP_get_hello (peer);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " updated mine to %p\n", mine);
- }
-}
-
-
-/******************************************************************************/
-/******************************** API
***********************************/
-/******************************************************************************/
-
-/**
- * Initialize the hello subsystem.
- *
- * @param c Configuration.
- */
-void
-GMH_init (const struct GNUNET_CONFIGURATION_Handle *c)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
- GNUNET_assert (NULL == nc);
- peerinfo = GNUNET_PEERINFO_connect (c);
- nc = GNUNET_PEERINFO_notify (c, GNUNET_NO, &got_hello, NULL);
-}
-
-
-/**
- * Shut down the hello subsystem.
- */
-void
-GMH_shutdown ()
-{
- if (NULL != nc)
- {
- GNUNET_PEERINFO_notify_cancel (nc);
- nc = NULL;
- }
- if (NULL != peerinfo)
- {
- GNUNET_PEERINFO_disconnect (peerinfo);
- peerinfo = NULL;
- }
-}
-
-
-/**
- * Get own hello message.
- *
- * @return Own hello message.
- */
-const struct GNUNET_HELLO_Message *
-GMH_get_mine (void)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, " mine is %p\n", mine);
- return mine;
-}
-
-
-/**
- * Get another peer's hello message.
- *
- * @param id ID of the peer whose hello message is requested.
- *
- * @return Hello message, if any (NULL possible).
- */
-const struct GNUNET_HELLO_Message *
-GMH_get (const struct GNUNET_PeerIdentity *id)
-{
- return GMP_get_hello (GMP_get (id));
-}
-
-
-/**
- * Convert a hello message to a string.
- *
- * @param h Hello message.
- */
-char *
-GMH_2s (const struct GNUNET_HELLO_Message *h)
-{
- return "hello (TODO)";
-}
-
-
Deleted: gnunet/src/mesh/gnunet-service-cadet_hello.h
===================================================================
--- gnunet/src/mesh/gnunet-service-cadet_hello.h 2014-05-07 12:07:02 UTC
(rev 33185)
+++ gnunet/src/mesh/gnunet-service-cadet_hello.h 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -1,76 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2014 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_hello.h
- * @brief cadet service; dealing with hello messages
- * @author Bartlomiej Polot
- *
- * All functions in this file should use the prefix GMH (Gnunet Cadet Hello)
- */
-
-#ifndef GNUNET_SERVICE_CADET_HELLO_H
-#define GNUNET_SERVICE_CADET_HELLO_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0 /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_hello_lib.h"
-
-
-/**
- * Initialize the hello subsystem.
- *
- * @param c Configuration.
- */
-void
-GMH_init (const struct GNUNET_CONFIGURATION_Handle *c);
-
-/**
- * Shut down the hello subsystem.
- */
-void
-GMH_shutdown ();
-
-/**
- * Get own hello message.
- *
- * @return Own hello message.
- */
-const struct GNUNET_HELLO_Message *
-GMH_get_mine (void);
-
-#if 0 /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_CADET_SERVICE_HELLO_H */
-#endif
-/* end of gnunet-cadet-service_hello.h */
Deleted: gnunet/src/mesh/gnunet-service-cadet_local.c
===================================================================
--- gnunet/src/mesh/gnunet-service-cadet_local.c 2014-05-07 12:07:02 UTC
(rev 33185)
+++ gnunet/src/mesh/gnunet-service-cadet_local.c 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -1,1242 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2013 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#include "gnunet_statistics_service.h"
-
-#include "cadet.h"
-#include "cadet_protocol.h" /* GNUNET_CADET_Data is shared */
-
-#include "gnunet-service-cadet_local.h"
-#include "gnunet-service-cadet_channel.h"
-
-/* INFO DEBUG */
-#include "gnunet-service-cadet_tunnel.h"
-#include "gnunet-service-cadet_peer.h"
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-loc",__VA_ARGS__)
-
-/******************************************************************************/
-/******************************** STRUCTS
**********************************/
-/******************************************************************************/
-
-/**
- * Struct containing information about a client of the service
- *
- * TODO: add a list of 'waiting' ports
- */
-struct CadetClient
-{
- /**
- * Linked list next
- */
- struct CadetClient *next;
-
- /**
- * Linked list prev
- */
- struct CadetClient *prev;
-
- /**
- * Tunnels that belong to this client, indexed by local id
- */
- struct GNUNET_CONTAINER_MultiHashMap32 *own_channels;
-
- /**
- * Tunnels this client has accepted, indexed by incoming local id
- */
- struct GNUNET_CONTAINER_MultiHashMap32 *incoming_channels;
-
- /**
- * Channel ID for the next incoming channel.
- */
- CADET_ChannelNumber next_chid;
-
- /**
- * Handle to communicate with the client
- */
- struct GNUNET_SERVER_Client *handle;
-
- /**
- * Ports that this client has declared interest in.
- * Indexed by port, contains *Client.
- */
- struct GNUNET_CONTAINER_MultiHashMap32 *ports;
-
- /**
- * Whether the client is active or shutting down (don't send confirmations
- * to a client that is shutting down.
- */
- int shutting_down;
-
- /**
- * ID of the client, mainly for debug messages
- */
- unsigned int id;
-};
-
-/******************************************************************************/
-/******************************* GLOBALS
***********************************/
-/******************************************************************************/
-
-/**
- * Global handle to the statistics service.
- */
-extern struct GNUNET_STATISTICS_Handle *stats;
-
-/**
- * Handle to server lib.
- */
-static struct GNUNET_SERVER_Handle *server_handle;
-
-/**
- * DLL with all the clients, head.
- */
-static struct CadetClient *clients_head;
-
-/**
- * DLL with all the clients, tail.
- */
-static struct CadetClient *clients_tail;
-
-/**
- * Next ID to assign to a client.
- */
-unsigned int next_client_id;
-
-/**
- * All ports clients of this peer have opened.
- */
-static struct GNUNET_CONTAINER_MultiHashMap32 *ports;
-
-/**
- * Notification context, to send messages to local clients.
- */
-static struct GNUNET_SERVER_NotificationContext *nc;
-
-
-/******************************************************************************/
-/******************************** STATIC
***********************************/
-/******************************************************************************/
-
-/**
- * Remove client's ports from the global hashmap on disconnect.
- *
- * @param cls Closure (unused).
- * @param key Port.
- * @param value Client structure.
- *
- * @return GNUNET_OK, keep iterating.
- */
-static int
-client_release_ports (void *cls,
- uint32_t key,
- void *value)
-{
- int res;
-
- res = GNUNET_CONTAINER_multihashmap32_remove (ports, key, value);
- if (GNUNET_YES != res)
- {
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "Port %u by client %p was not registered.\n",
- key, value);
- }
- return GNUNET_OK;
-}
-
-
-
-/******************************************************************************/
-/******************************** HANDLES
***********************************/
-/******************************************************************************/
-
-
-/**
- * Handler for client connection.
- *
- * @param cls Closure (unused).
- * @param client Client handler.
- */
-static void
-handle_client_connect (void *cls, struct GNUNET_SERVER_Client *client)
-{
- struct CadetClient *c;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "client connected: %p\n", client);
- if (NULL == client)
- return;
- c = GNUNET_new (struct CadetClient);
- c->handle = client;
- c->id = next_client_id++; /* overflow not important: just for debug */
- c->next_chid = GNUNET_CADET_LOCAL_CHANNEL_ID_SERV;
- GNUNET_SERVER_client_keep (client);
- GNUNET_SERVER_client_set_user_context (client, c);
- GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, c);
-}
-
-
-/**
- * Iterator for deleting each channel whose client endpoint disconnected.
- *
- * @param cls Closure (client that has disconnected).
- * @param key The local channel id (used to access the hashmap).
- * @param value The value stored at the key (channel to destroy).
- *
- * @return GNUNET_OK, keep iterating.
- */
-static int
-channel_destroy_iterator (void *cls,
- uint32_t key,
- void *value)
-{
- struct CadetChannel *ch = value;
- struct CadetClient *c = cls;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " Channel %s destroy, due to client %s shutdown.\n",
- GMCH_2s (ch), GML_2s (c));
-
- GMCH_handle_local_destroy (ch, c, key < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV);
- return GNUNET_OK;
-}
-
-/**
- * Handler for client disconnection
- *
- * @param cls closure
- * @param client identification of the client; NULL
- * for the last call when the server is destroyed
- */
-static void
-handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
-{
- struct CadetClient *c;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "client disconnected: %p\n", client);
- if (client == NULL)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " (SERVER DOWN)\n");
- return;
- }
-
- c = GML_client_get (client);
- if (NULL != c)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "matching client found (%u, %p)\n",
- c->id, c);
- GNUNET_SERVER_client_drop (c->handle);
- c->shutting_down = GNUNET_YES;
- if (NULL != c->own_channels)
- {
- GNUNET_CONTAINER_multihashmap32_iterate (c->own_channels,
- &channel_destroy_iterator, c);
- GNUNET_CONTAINER_multihashmap32_destroy (c->own_channels);
- }
-
- if (NULL != c->incoming_channels)
- {
- GNUNET_CONTAINER_multihashmap32_iterate (c->incoming_channels,
- &channel_destroy_iterator, c);
- GNUNET_CONTAINER_multihashmap32_destroy (c->incoming_channels);
- }
-
- if (NULL != c->ports)
- {
- GNUNET_CONTAINER_multihashmap32_iterate (c->ports,
- &client_release_ports, c);
- GNUNET_CONTAINER_multihashmap32_destroy (c->ports);
- }
- GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, c);
- GNUNET_STATISTICS_update (stats, "# clients", -1, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " client free (%p)\n", c);
- GNUNET_free (c);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_WARNING, " context NULL!\n");
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "done!\n");
- return;
-}
-
-
-/**
- * Handler for new clients
- *
- * @param cls closure
- * @param client identification of the client
- * @param message the actual message, which includes messages the client wants
- */
-static void
-handle_new_client (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- struct GNUNET_CADET_ClientConnect *cc_msg;
- struct CadetClient *c;
- unsigned int size;
- uint32_t *p;
- unsigned int i;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, "new client connected %p\n", client);
-
- /* Check data sanity */
- size = ntohs (message->size) - sizeof (struct GNUNET_CADET_ClientConnect);
- cc_msg = (struct GNUNET_CADET_ClientConnect *) message;
- if (0 != (size % sizeof (uint32_t)))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
- size /= sizeof (uint32_t);
-
- /* Initialize new client structure */
- c = GNUNET_SERVER_client_get_user_context (client, struct CadetClient);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " client id %u\n", c->id);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " client has %u ports\n", size);
- if (size > 0)
- {
- uint32_t u32;
-
- p = (uint32_t *) &cc_msg[1];
- c->ports = GNUNET_CONTAINER_multihashmap32_create (size);
- for (i = 0; i < size; i++)
- {
- u32 = ntohl (p[i]);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " port: %u\n", u32);
-
- /* store in client's hashmap */
- GNUNET_CONTAINER_multihashmap32_put (c->ports, u32, c,
-
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
- /* store in global hashmap */
- /* FIXME only allow one client to have the port open,
- * have a backup hashmap with waiting clients */
- GNUNET_CONTAINER_multihashmap32_put (ports, u32, c,
-
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
- }
- }
-
- c->own_channels = GNUNET_CONTAINER_multihashmap32_create (32);
- c->incoming_channels = GNUNET_CONTAINER_multihashmap32_create (32);
- GNUNET_SERVER_notification_context_add (nc, client);
- GNUNET_STATISTICS_update (stats, "# clients", 1, GNUNET_NO);
-
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "new client processed\n");
-}
-
-
-/**
- * Handler for requests of new tunnels
- *
- * @param cls Closure.
- * @param client Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_channel_create (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- struct CadetClient *c;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, "new channel requested\n");
-
- /* Sanity check for client registration */
- if (NULL == (c = GML_client_get (client)))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id);
-
- /* Message size sanity check */
- if (sizeof (struct GNUNET_CADET_ChannelMessage) != ntohs (message->size))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
-
- if (GNUNET_OK !=
- GMCH_handle_local_create (c,
- (struct GNUNET_CADET_ChannelMessage *)
message))
- {
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
-
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
-}
-
-
-/**
- * Handler for requests of deleting tunnels
- *
- * @param cls closure
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-handle_channel_destroy (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- struct GNUNET_CADET_ChannelMessage *msg;
- struct CadetClient *c;
- struct CadetChannel *ch;
- CADET_ChannelNumber chid;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a DESTROY CHANNEL from client!\n");
-
- /* Sanity check for client registration */
- if (NULL == (c = GML_client_get (client)))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id);
-
- /* Message sanity check */
- if (sizeof (struct GNUNET_CADET_ChannelMessage) != ntohs (message->size))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
-
- msg = (struct GNUNET_CADET_ChannelMessage *) message;
-
- /* Retrieve tunnel */
- chid = ntohl (msg->channel_id);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " for channel %X\n", chid);
- ch = GML_channel_get (c, chid);
- if (NULL == ch)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " channel %X not found\n", chid);
- GNUNET_STATISTICS_update (stats,
- "# client destroy messages on unknown channel",
- 1, GNUNET_NO);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
- }
-
- GMCH_handle_local_destroy (ch, c, chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV);
-
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
-}
-
-
-/**
- * Handler for client traffic
- *
- * @param cls closure
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-handle_data (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- struct GNUNET_CADET_LocalData *msg;
- struct CadetClient *c;
- struct CadetChannel *ch;
- CADET_ChannelNumber chid;
- size_t size;
- int fwd;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Got data from a client!\n");
-
- /* Sanity check for client registration */
- if (NULL == (c = GML_client_get (client)))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id);
-
- msg = (struct GNUNET_CADET_LocalData *) message;
-
- /* Sanity check for message size */
- size = ntohs (message->size) - sizeof (struct GNUNET_CADET_LocalData);
- if (size < sizeof (struct GNUNET_MessageHeader))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
-
- /* Channel exists? */
- chid = ntohl (msg->id);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X\n", chid);
- fwd = chid < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV;
- ch = GML_channel_get (c, chid);
- if (NULL == ch)
- {
- GNUNET_STATISTICS_update (stats,
- "# client data messages on unknown channel",
- 1, GNUNET_NO);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
- }
-
- if (GNUNET_OK !=
- GMCH_handle_local_data (ch, c,
- (struct GNUNET_MessageHeader *)&msg[1], fwd))
- {
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "receive done OK\n");
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-
- return;
-}
-
-
-/**
- * Handler for client's ACKs for payload traffic.
- *
- * @param cls Closure (unused).
- * @param client Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_ack (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- struct GNUNET_CADET_LocalAck *msg;
- struct CadetChannel *ch;
- struct CadetClient *c;
- CADET_ChannelNumber chid;
- int fwd;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a local ACK\n");
-
- /* Sanity check for client registration */
- if (NULL == (c = GML_client_get (client)))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id);
-
- msg = (struct GNUNET_CADET_LocalAck *) message;
-
- /* Channel exists? */
- chid = ntohl (msg->channel_id);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X\n", chid);
- ch = GML_channel_get (c, chid);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " -- ch %p\n", ch);
- if (NULL == ch)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %X unknown.\n", chid);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " for client %u.\n", c->id);
- GNUNET_STATISTICS_update (stats,
- "# client ack messages on unknown channel",
- 1, GNUNET_NO);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
- }
-
- /* If client is root, the ACK is going FWD, therefore this is "BCK ACK". */
- /* If client is dest, the ACK is going BCK, therefore this is "FWD ACK" */
- fwd = chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV;
-
- GMCH_handle_local_ack (ch, fwd);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-
- return;
-}
-
-
-
-/**
- * Iterator over all peers to send a monitoring client info about each peer.
- *
- * @param cls Closure ().
- * @param peer Peer ID (tunnel remote peer).
- * @param value Peer info.
- *
- * @return #GNUNET_YES, to keep iterating.
- */
-static int
-get_all_peers_iterator (void *cls,
- const struct GNUNET_PeerIdentity * peer,
- void *value)
-{
- struct GNUNET_SERVER_Client *client = cls;
- struct CadetPeer *p = value;
- struct GNUNET_CADET_LocalInfoPeer msg;
-
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
- msg.destination = *peer;
- msg.paths = htons (GMP_count_paths (p));
- msg.tunnel = htons (NULL != GMP_get_tunnel (p));
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "sending info about peer %s\n",
- GNUNET_i2s (peer));
-
- GNUNET_SERVER_notification_context_unicast (nc, client,
- &msg.header, GNUNET_NO);
- return GNUNET_YES;
-}
-
-
-/**
- * Handler for client's INFO PEERS request.
- *
- * @param cls Closure (unused).
- * @param client Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_get_peers (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- struct CadetClient *c;
- struct GNUNET_MessageHeader reply;
-
- /* Sanity check for client registration */
- if (NULL == (c = GML_client_get (client)))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Received get peers request from client %u (%p)\n",
- c->id, client);
-
- GMP_iterate_all (get_all_peers_iterator, client);
- reply.size = htons (sizeof (reply));
- reply.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
- GNUNET_SERVER_notification_context_unicast (nc, client, &reply, GNUNET_NO);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Get peers request from client %u completed\n", c->id);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Iterator over all tunnels to send a monitoring client info about each
tunnel.
- *
- * @param cls Closure ().
- * @param peer Peer ID (tunnel remote peer).
- * @param value Tunnel info.
- *
- * @return #GNUNET_YES, to keep iterating.
- */
-static int
-get_all_tunnels_iterator (void *cls,
- const struct GNUNET_PeerIdentity * peer,
- void *value)
-{
- struct GNUNET_SERVER_Client *client = cls;
- struct CadetTunnel3 *t = value;
- struct GNUNET_CADET_LocalInfoTunnel msg;
-
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
- msg.destination = *peer;
- msg.channels = htonl (GMT_count_channels (t));
- msg.connections = htonl (GMT_count_connections (t));
- msg.cstate = htons ((uint16_t) GMT_get_cstate (t));
- msg.estate = htons ((uint16_t) GMT_get_estate (t));
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "sending info about tunnel ->%s\n",
- GNUNET_i2s (peer));
-
- GNUNET_SERVER_notification_context_unicast (nc, client,
- &msg.header, GNUNET_NO);
- return GNUNET_YES;
-}
-
-
-/**
- * Handler for client's INFO TUNNELS request.
- *
- * @param cls Closure (unused).
- * @param client Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_get_tunnels (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- struct CadetClient *c;
- struct GNUNET_MessageHeader reply;
-
- /* Sanity check for client registration */
- if (NULL == (c = GML_client_get (client)))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Received get tunnels request from client %u (%p)\n",
- c->id, client);
-
- GMT_iterate_all (get_all_tunnels_iterator, client);
- reply.size = htons (sizeof (reply));
- reply.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
- GNUNET_SERVER_notification_context_unicast (nc, client, &reply, GNUNET_NO);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Get tunnels request from client %u completed\n", c->id);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-static void
-iter_connection (void *cls, struct CadetConnection *c)
-{
- struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
- struct GNUNET_CADET_Hash *h = (struct GNUNET_CADET_Hash *) &msg[1];
-
- h[msg->connections] = *(GMC_get_id (c));
- msg->connections++;
-}
-
-static void
-iter_channel (void *cls, struct CadetChannel *ch)
-{
- struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
- struct GNUNET_HashCode *h = (struct GNUNET_HashCode *) &msg[1];
- CADET_ChannelNumber *chn = (CADET_ChannelNumber *) &h[msg->connections];
-
- chn[msg->channels] = GMCH_get_id (ch);
- msg->channels++;
-}
-
-
-/**
- * Handler for client's SHOW_TUNNEL request.
- *
- * @param cls Closure (unused).
- * @param client Identification of the client.
- * @param message The actual message.
- */
-void
-handle_show_tunnel (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- const struct GNUNET_CADET_LocalInfo *msg;
- struct GNUNET_CADET_LocalInfoTunnel *resp;
- struct CadetClient *c;
- struct CadetTunnel3 *t;
- unsigned int ch_n;
- unsigned int c_n;
- size_t size;
-
- /* Sanity check for client registration */
- if (NULL == (c = GML_client_get (client)))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
-
- msg = (struct GNUNET_CADET_LocalInfo *) message;
- LOG (GNUNET_ERROR_TYPE_INFO,
- "Received tunnel info request from client %u for tunnel %s\n",
- c->id, GNUNET_i2s_full(&msg->peer));
-
- t = GMP_get_tunnel (GMP_get (&msg->peer));
- if (NULL == t)
- {
- /* We don't know the tunnel */
- struct GNUNET_CADET_LocalInfoTunnel warn;
-
- LOG (GNUNET_ERROR_TYPE_INFO, "Tunnel %s unknown %u\n",
- GNUNET_i2s_full(&msg->peer), sizeof (warn));
- warn.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
- warn.header.size = htons (sizeof (warn));
- warn.destination = msg->peer;
- warn.channels = htonl (0);
- warn.connections = htonl (0);
- warn.cstate = htons (0);
- warn.estate = htons (0);
-
- GNUNET_SERVER_notification_context_unicast (nc, client,
- &warn.header,
- GNUNET_NO);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
- }
-
- /* Initialize context */
- ch_n = GMT_count_channels (t);
- c_n = GMT_count_connections (t);
-
- size = sizeof (struct GNUNET_CADET_LocalInfoTunnel);
- size += c_n * sizeof (struct GNUNET_CADET_Hash);
- size += ch_n * sizeof (CADET_ChannelNumber);
-
- resp = GNUNET_malloc (size);
- resp->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
- resp->header.size = htons (size);
- GMT_iterate_connections (t, &iter_connection, resp);
- GMT_iterate_channels (t, &iter_channel, resp);
- /* Do not interleave with iterators, iter_channel needs conn in HBO */
- resp->destination = msg->peer;
- resp->connections = htonl (resp->connections);
- resp->channels = htonl (resp->channels);
- resp->cstate = htons (GMT_get_cstate (t));
- resp->estate = htons (GMT_get_estate (t));
- GNUNET_SERVER_notification_context_unicast (nc, c->handle,
- &resp->header, GNUNET_NO);
- GNUNET_free (resp);
-
- LOG (GNUNET_ERROR_TYPE_INFO,
- "Show tunnel request from client %u completed. %u conn, %u ch\n",
- c->id, c_n, ch_n);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Functions to handle messages from clients
- */
-static struct GNUNET_SERVER_MessageHandler client_handlers[] = {
- {&handle_new_client, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_CONNECT, 0},
- {&handle_channel_create, NULL, GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE,
- sizeof (struct GNUNET_CADET_ChannelMessage)},
- {&handle_channel_destroy, NULL, GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY,
- sizeof (struct GNUNET_CADET_ChannelMessage)},
- {&handle_data, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA, 0},
- {&handle_ack, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
- sizeof (struct GNUNET_CADET_LocalAck)},
- {&handle_get_peers, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
- sizeof (struct GNUNET_MessageHeader)},
- {&handle_get_tunnels, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
- sizeof (struct GNUNET_MessageHeader)},
- {&handle_show_tunnel, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
- sizeof (struct GNUNET_CADET_LocalInfo)},
- {NULL, NULL, 0, 0}
-};
-
-
-
-/******************************************************************************/
-/******************************** API
***********************************/
-/******************************************************************************/
-
-/**
- * Initialize server subsystem.
- *
- * @param handle Server handle.
- */
-void
-GML_init (struct GNUNET_SERVER_Handle *handle)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
- server_handle = handle;
- GNUNET_SERVER_suspend (server_handle);
- ports = GNUNET_CONTAINER_multihashmap32_create (32);
-}
-
-
-/**
- * Install server (service) handlers and start listening to clients.
- */
-void
-GML_start (void)
-{
- GNUNET_SERVER_add_handlers (server_handle, client_handlers);
- GNUNET_SERVER_connect_notify (server_handle, &handle_client_connect, NULL);
- GNUNET_SERVER_disconnect_notify (server_handle, &handle_client_disconnect,
- NULL);
- nc = GNUNET_SERVER_notification_context_create (server_handle, 1);
-
- clients_head = NULL;
- clients_tail = NULL;
- next_client_id = 0;
- GNUNET_SERVER_resume (server_handle);
-}
-
-
-/**
- * Shutdown server.
- */
-void
-GML_shutdown (void)
-{
- if (nc != NULL)
- {
- GNUNET_SERVER_notification_context_destroy (nc);
- nc = NULL;
- }
-}
-
-
-/**
- * Get a channel from a client.
- *
- * @param c Client to check.
- * @param chid Channel ID, must be local (> 0x800...).
- *
- * @return non-NULL if channel exists in the clients lists
- */
-struct CadetChannel *
-GML_channel_get (struct CadetClient *c, CADET_ChannelNumber chid)
-{
- struct GNUNET_CONTAINER_MultiHashMap32 *map;
-
- if (0 == (chid & GNUNET_CADET_LOCAL_CHANNEL_ID_CLI))
- {
- GNUNET_break_op (0);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "CHID %X not a local chid\n", chid);
- return NULL;
- }
-
- if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV)
- map = c->incoming_channels;
- else if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
- map = c->own_channels;
- else
- {
- GNUNET_break (0);
- map = NULL;
- }
- if (NULL == map)
- {
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Client %s does no t have a valid map for CHID %X\n",
- GML_2s (c), chid);
- return NULL;
- }
- return GNUNET_CONTAINER_multihashmap32_get (map, chid);
-}
-
-
-/**
- * Add a channel to a client
- *
- * @param client Client.
- * @param chid Channel ID.
- * @param ch Channel.
- */
-void
-GML_channel_add (struct CadetClient *client,
- uint32_t chid,
- struct CadetChannel *ch)
-{
- if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV)
- GNUNET_CONTAINER_multihashmap32_put (client->incoming_channels, chid, ch,
-
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
- else if (chid >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
- GNUNET_CONTAINER_multihashmap32_put (client->own_channels, chid, ch,
-
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
- else
- GNUNET_break (0);
-}
-
-
-/**
- * Remove a channel from a client.
- *
- * @param client Client.
- * @param chid Channel ID.
- * @param ch Channel.
- */
-void
-GML_channel_remove (struct CadetClient *client,
- uint32_t chid,
- struct CadetChannel *ch)
-{
- if (GNUNET_CADET_LOCAL_CHANNEL_ID_SERV <= chid)
- GNUNET_break (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap32_remove
(client->incoming_channels,
- chid, ch));
- else if (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI <= chid)
- GNUNET_break (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap32_remove (client->own_channels,
- chid, ch));
- else
- GNUNET_break (0);
-}
-
-
-/**
- * Get the tunnel's next free local channel ID.
- *
- * @param c Client.
- *
- * @return LID of a channel free to use.
- */
-CADET_ChannelNumber
-GML_get_next_chid (struct CadetClient *c)
-{
- CADET_ChannelNumber chid;
-
- while (NULL != GML_channel_get (c, c->next_chid))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %u exists...\n", c->next_chid);
- c->next_chid = (c->next_chid + 1) | GNUNET_CADET_LOCAL_CHANNEL_ID_SERV;
- }
- chid = c->next_chid;
- c->next_chid = (c->next_chid + 1) | GNUNET_CADET_LOCAL_CHANNEL_ID_SERV;
-
- return chid;
-}
-
-
-/**
- * Check if client has registered with the service and has not disconnected
- *
- * @param client the client to check
- *
- * @return non-NULL if client exists in the global DLL
- */
-struct CadetClient *
-GML_client_get (struct GNUNET_SERVER_Client *client)
-{
- return GNUNET_SERVER_client_get_user_context (client, struct CadetClient);
-}
-
-/**
- * Find a client that has opened a port
- *
- * @param port Port to check.
- *
- * @return non-NULL if a client has the port.
- */
-struct CadetClient *
-GML_client_get_by_port (uint32_t port)
-{
- return GNUNET_CONTAINER_multihashmap32_get (ports, port);
-}
-
-
-/**
- * Deletes a channel from a client (either owner or destination).
- *
- * @param c Client whose tunnel to delete.
- * @param ch Channel which should be deleted.
- * @param id Channel ID.
- */
-void
-GML_client_delete_channel (struct CadetClient *c,
- struct CadetChannel *ch,
- CADET_ChannelNumber id)
-{
- int res;
-
- if (GNUNET_CADET_LOCAL_CHANNEL_ID_SERV <= id)
- {
- res = GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels,
- id, ch);
- if (GNUNET_YES != res)
- LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_channel dest KO\n");
- }
- else if (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI <= id)
- {
- res = GNUNET_CONTAINER_multihashmap32_remove (c->own_channels,
- id, ch);
- if (GNUNET_YES != res)
- LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_tunnel root KO\n");
- }
- else
- {
- GNUNET_break (0);
- }
-}
-
-/**
- * Build a local ACK message and send it to a local client, if needed.
- *
- * If the client was already allowed to send data, do nothing.
- *
- * @param c Client to whom send the ACK.
- * @param id Channel ID to use
- */
-void
-GML_send_ack (struct CadetClient *c, CADET_ChannelNumber id)
-{
- struct GNUNET_CADET_LocalAck msg;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "send local %s ack on %X towards %p\n",
- id < GNUNET_CADET_LOCAL_CHANNEL_ID_SERV ? "FWD" : "BCK", id, c);
-
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
- msg.channel_id = htonl (id);
- GNUNET_SERVER_notification_context_unicast (nc,
- c->handle,
- &msg.header,
- GNUNET_NO);
-
-}
-
-
-
-/**
- * Notify the client that a new incoming channel was created.
- *
- * @param c Client to notify.
- * @param id Channel ID.
- * @param port Channel's destination port.
- * @param opt Options (bit array).
- * @param peer Origin peer.
- */
-void
-GML_send_channel_create (struct CadetClient *c,
- uint32_t id, uint32_t port, uint32_t opt,
- const struct GNUNET_PeerIdentity *peer)
-{
- struct GNUNET_CADET_ChannelMessage msg;
-
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE);
- msg.channel_id = htonl (id);
- msg.port = htonl (port);
- msg.opt = htonl (opt);
- msg.peer = *peer;
- GNUNET_SERVER_notification_context_unicast (nc, c->handle,
- &msg.header, GNUNET_NO);
-}
-
-
-/**
- * Build a local channel NACK message and send it to a local client.
- *
- * @param c Client to whom send the NACK.
- * @param id Channel ID to use
- */
-void
-GML_send_channel_nack (struct CadetClient *c, CADET_ChannelNumber id)
-{
- struct GNUNET_CADET_LocalAck msg;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "send local nack on %X towards %p\n",
- id, c);
-
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK);
- msg.channel_id = htonl (id);
- GNUNET_SERVER_notification_context_unicast (nc,
- c->handle,
- &msg.header,
- GNUNET_NO);
-
-}
-
-/**
- * Notify a client that a channel is no longer valid.
- *
- * @param c Client.
- * @param id ID of the channel that is destroyed.
- */
-void
-GML_send_channel_destroy (struct CadetClient *c, uint32_t id)
-{
- struct GNUNET_CADET_ChannelMessage msg;
-
- if (NULL == c)
- {
- GNUNET_break (0);
- return;
- }
- if (GNUNET_YES == c->shutting_down)
- return;
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
- msg.channel_id = htonl (id);
- msg.port = htonl (0);
- memset (&msg.peer, 0, sizeof (msg.peer));
- msg.opt = htonl (0);
- GNUNET_SERVER_notification_context_unicast (nc, c->handle,
- &msg.header, GNUNET_NO);
-}
-
-
-/**
- * Modify the cadet message ID from global to local and send to client.
- *
- * @param c Client to send to.
- * @param msg Message to modify and send.
- * @param id Channel ID to use (c can be both owner and client).
- */
-void
-GML_send_data (struct CadetClient *c,
- const struct GNUNET_CADET_Data *msg,
- CADET_ChannelNumber id)
-{
- struct GNUNET_CADET_LocalData *copy;
- uint16_t size = ntohs (msg->header.size) - sizeof (struct GNUNET_CADET_Data);
- char cbuf[size + sizeof (struct GNUNET_CADET_LocalData)];
-
- if (size < sizeof (struct GNUNET_MessageHeader))
- {
- GNUNET_break_op (0);
- return;
- }
- if (NULL == c)
- {
- GNUNET_break (0);
- return;
- }
- copy = (struct GNUNET_CADET_LocalData *) cbuf;
- memcpy (©[1], &msg[1], size);
- copy->header.size = htons (sizeof (struct GNUNET_CADET_LocalData) + size);
- copy->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
- copy->id = htonl (id);
- GNUNET_SERVER_notification_context_unicast (nc, c->handle,
- ©->header, GNUNET_NO);
-}
-
-
-/**
- * Get the static string to represent a client.
- *
- * @param c Client.
- *
- * @return Static string for the client.
- */
-const char *
-GML_2s (const struct CadetClient *c)
-{
- static char buf[32];
-
- sprintf (buf, "%u", c->id);
- return buf;
-}
Deleted: gnunet/src/mesh/gnunet-service-cadet_local.h
===================================================================
--- gnunet/src/mesh/gnunet-service-cadet_local.h 2014-05-07 12:07:02 UTC
(rev 33185)
+++ gnunet/src/mesh/gnunet-service-cadet_local.h 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -1,226 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2013 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_local.h
- * @brief cadet service; dealing with local clients
- * @author Bartlomiej Polot
- *
- * All functions in this file should use the prefix GML (Gnunet Cadet Local)
- */
-
-#ifndef GNUNET_SERVICE_CADET_LOCAL_H
-#define GNUNET_SERVICE_CADET_LOCAL_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0 /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-/**
- * Struct containing information about a client of the service
- */
-struct CadetClient;
-
-#include "gnunet-service-cadet_channel.h"
-
-/******************************************************************************/
-/******************************** API
***********************************/
-/******************************************************************************/
-
-/**
- * Initialize server subsystem.
- *
- * @param handle Server handle.
- */
-void
-GML_init (struct GNUNET_SERVER_Handle *handle);
-
-/**
- * Install server (service) handlers and start listening to clients.
- */
-void
-GML_start (void);
-
-/**
- * Shutdown server.
- */
-void
-GML_shutdown (void);
-
-/**
- * Get a channel from a client.
- *
- * @param c Client to check.
- * @param chid Channel ID, must be local (> 0x800...).
- *
- * @return non-NULL if channel exists in the clients lists
- */
-struct CadetChannel *
-GML_channel_get (struct CadetClient *c, uint32_t chid);
-
-/**
- * Add a channel to a client
- *
- * @param client Client.
- * @param chid Channel ID.
- * @param ch Channel.
- */
-void
-GML_channel_add (struct CadetClient *client,
- uint32_t chid,
- struct CadetChannel *ch);
-
-/**
- * Remove a channel from a client
- *
- * @param client Client.
- * @param chid Channel ID.
- * @param ch Channel.
- */
-void
-GML_channel_remove (struct CadetClient *client,
- uint32_t chid,
- struct CadetChannel *ch);
-
-/**
- * Get the tunnel's next free local channel ID.
- *
- * @param c Client.
- *
- * @return LID of a channel free to use.
- */
-CADET_ChannelNumber
-GML_get_next_chid (struct CadetClient *c);
-
-/**
- * Check if client has registered with the service and has not disconnected
- *
- * @param client the client to check
- *
- * @return non-NULL if client exists in the global DLL
- */
-struct CadetClient *
-GML_client_get (struct GNUNET_SERVER_Client *client);
-
-/**
- * Find a client that has opened a port
- *
- * @param port Port to check.
- *
- * @return non-NULL if a client has the port.
- */
-struct CadetClient *
-GML_client_get_by_port (uint32_t port);
-
-/**
- * Deletes a tunnel from a client (either owner or destination).
- *
- * @param c Client whose tunnel to delete.
- * @param ch Channel which should be deleted.
- * @param id Channel ID.
- */
-void
-GML_client_delete_channel (struct CadetClient *c,
- struct CadetChannel *ch,
- CADET_ChannelNumber id);
-
-/**
- * Build a local ACK message and send it to a local client, if needed.
- *
- * If the client was already allowed to send data, do nothing.
- *
- * @param c Client to whom send the ACK.
- * @param id Channel ID to use
- */
-void
-GML_send_ack (struct CadetClient *c, CADET_ChannelNumber id);
-
-/**
- * Notify the appropriate client that a new incoming channel was created.
- *
- * @param c Client to notify.
- * @param id Channel ID.
- * @param port Channel's destination port.
- * @param opt Options (bit array).
- * @param peer Origin peer.
- */
-void
-GML_send_channel_create (struct CadetClient *c,
- uint32_t id, uint32_t port, uint32_t opt,
- const struct GNUNET_PeerIdentity *peer);
-
-/**
- * Build a local channel NACK message and send it to a local client.
- *
- * @param c Client to whom send the NACK.
- * @param id Channel ID to use
- */
-void
-GML_send_channel_nack (struct CadetClient *c, CADET_ChannelNumber id);
-
-/**
- * Notify a client that a channel is no longer valid.
- *
- * @param c Client.
- * @param id ID of the channel that is destroyed.
- */
-void
-GML_send_channel_destroy (struct CadetClient *c, uint32_t id);
-
-/**
- * Modify the cadet message ID from global to local and send to client.
- *
- * @param c Client to send to.
- * @param msg Message to modify and send.
- * @param id Channel ID to use (c can be both owner and client).
- */
-void
-GML_send_data (struct CadetClient *c,
- const struct GNUNET_CADET_Data *msg,
- CADET_ChannelNumber id);
-
-/**
- * Get the static string to represent a client.
- *
- * @param c Client.
- *
- * @return Static string for the client.
- */
-const char *
-GML_2s (const struct CadetClient *c);
-
-
-#if 0 /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_CADET_SERVICE_LOCAL_H */
-#endif
-/* end of gnunet-cadet-service_LOCAL.h */
Deleted: gnunet/src/mesh/gnunet-service-cadet_peer.c
===================================================================
--- gnunet/src/mesh/gnunet-service-cadet_peer.c 2014-05-07 12:07:02 UTC (rev
33185)
+++ gnunet/src/mesh/gnunet-service-cadet_peer.c 2014-05-07 12:07:16 UTC (rev
33186)
@@ -1,2219 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2013 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#include "gnunet_transport_service.h"
-#include "gnunet_core_service.h"
-#include "gnunet_statistics_service.h"
-
-#include "cadet_protocol.h"
-
-#include "gnunet-service-cadet_peer.h"
-#include "gnunet-service-cadet_dht.h"
-#include "gnunet-service-cadet_connection.h"
-#include "gnunet-service-cadet_tunnel.h"
-#include "cadet_path.h"
-
-#define LOG(level, ...) GNUNET_log_from (level,"cadet-p2p",__VA_ARGS__)
-
-/******************************************************************************/
-/******************************** STRUCTS
**********************************/
-/******************************************************************************/
-
-/**
- * Struct containing info about a queued transmission to this peer
- */
-struct CadetPeerQueue
-{
- /**
- * DLL next
- */
- struct CadetPeerQueue *next;
-
- /**
- * DLL previous
- */
- struct CadetPeerQueue *prev;
-
- /**
- * Peer this transmission is directed to.
- */
- struct CadetPeer *peer;
-
- /**
- * Connection this message belongs to.
- */
- struct CadetConnection *c;
-
- /**
- * Is FWD in c?
- */
- int fwd;
-
- /**
- * Pointer to info stucture used as cls.
- */
- void *cls;
-
- /**
- * Type of message
- */
- uint16_t type;
-
- /**
- * Type of message
- */
- uint16_t payload_type;
-
- /**
- * Type of message
- */
- uint32_t payload_id;
-
- /**
- * Size of the message
- */
- size_t size;
-
- /**
- * Set when this message starts waiting for CORE.
- */
- struct GNUNET_TIME_Absolute start_waiting;
-
- /**
- * Function to call on sending.
- */
- GMP_sent callback;
-
- /**
- * Closure for callback.
- */
- void *callback_cls;
-};
-
-/**
- * Struct containing all information regarding a given peer
- */
-struct CadetPeer
-{
- /**
- * ID of the peer
- */
- GNUNET_PEER_Id id;
-
- /**
- * Last time we heard from this peer
- */
- struct GNUNET_TIME_Absolute last_contact;
-
- /**
- * Paths to reach the peer, ordered by ascending hop count
- */
- struct CadetPeerPath *path_head;
-
- /**
- * Paths to reach the peer, ordered by ascending hop count
- */
- struct CadetPeerPath *path_tail;
-
- /**
- * Handle to stop the DHT search for paths to this peer
- */
- struct GMD_search_handle *search_h;
-
- /**
- * Tunnel to this peer, if any.
- */
- struct CadetTunnel3 *tunnel;
-
- /**
- * Connections that go through this peer, indexed by tid;
- */
- struct GNUNET_CONTAINER_MultiHashMap *connections;
-
- /**
- * Handle for queued transmissions
- */
- struct GNUNET_CORE_TransmitHandle *core_transmit;
-
- /**
- * Transmission queue to core DLL head
- */
- struct CadetPeerQueue *queue_head;
-
- /**
- * Transmission queue to core DLL tail
- */
- struct CadetPeerQueue *queue_tail;
-
- /**
- * How many messages are in the queue to this peer.
- */
- unsigned int queue_n;
-
- /**
- * Hello message.
- */
- struct GNUNET_HELLO_Message* hello;
-};
-
-
-/******************************************************************************/
-/******************************* GLOBALS
***********************************/
-/******************************************************************************/
-
-/**
- * Global handle to the statistics service.
- */
-extern struct GNUNET_STATISTICS_Handle *stats;
-
-/**
- * Local peer own ID (full value).
- */
-extern struct GNUNET_PeerIdentity my_full_id;
-
-/**
- * Local peer own ID (short)
- */
-extern GNUNET_PEER_Id myid;
-
-/**
- * Peers known, indexed by PeerIdentity (CadetPeer).
- */
-static struct GNUNET_CONTAINER_MultiPeerMap *peers;
-
-/**
- * How many peers do we want to remember?
- */
-static unsigned long long max_peers;
-
-/**
- * Percentage of messages that will be dropped (for test purposes only).
- */
-static unsigned long long drop_percent;
-
-/**
- * Handle to communicate with core.
- */
-static struct GNUNET_CORE_Handle *core_handle;
-
-/**
- * Handle to try to start new connections.
- */
-static struct GNUNET_TRANSPORT_Handle *transport_handle;
-
-
-/******************************************************************************/
-/***************************** DEBUG
*********************************/
-/******************************************************************************/
-
-static void
-queue_debug (struct CadetPeer *peer)
-{
- struct CadetPeerQueue *q;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "QQQ Messages queued towards %s\n", GMP_2s
(peer));
- LOG (GNUNET_ERROR_TYPE_DEBUG, "QQQ core tmt rdy: %p\n",
peer->core_transmit);
-
- for (q = peer->queue_head; NULL != q; q = q->next)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "QQQ - %s %s on %s\n",
- GM_m2s (q->type), GM_f2s (q->fwd), GMC_2s (q->c));
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "QQQ End queued towards %s\n", GMP_2s (peer));
-}
-
-
-/******************************************************************************/
-/***************************** CORE HELPERS
*********************************/
-/******************************************************************************/
-
-
-/**
- * Iterator to notify all connections of a broken link. Mark connections
- * to destroy after all traffic has been sent.
- *
- * @param cls Closure (peer disconnected).
- * @param key Current key code (peer id).
- * @param value Value in the hash map (connection).
- *
- * @return #GNUNET_YES to continue to iterate.
- */
-static int
-notify_broken (void *cls,
- const struct GNUNET_HashCode *key,
- void *value)
-{
- struct CadetPeer *peer = cls;
- struct CadetConnection *c = value;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " notifying %s due to %s\n",
- GMC_2s (c), GMP_2s (peer));
- GMC_notify_broken (c, peer);
-
- return GNUNET_YES;
-}
-
-
-/**
- * Remove the direct path to the peer.
- *
- * @param peer Peer to remove the direct path from.
- *
- */
-static struct CadetPeerPath *
-pop_direct_path (struct CadetPeer *peer)
-{
- struct CadetPeerPath *iter;
-
- for (iter = peer->path_head; NULL != iter; iter = iter->next)
- {
- if (2 <= iter->length)
- {
- GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, iter);
- return iter;
- }
- }
- return NULL;
-}
-
-
-/******************************************************************************/
-/***************************** CORE CALLBACKS
*********************************/
-/******************************************************************************/
-
-/**
- * Method called whenever a given peer connects.
- *
- * @param cls closure
- * @param peer peer identity this notification is about
- */
-static void
-core_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
-{
- struct CadetPeer *mp;
- struct CadetPeerPath *path;
- char own_id[16];
-
- strncpy (own_id, GNUNET_i2s (&my_full_id), 15);
- mp = GMP_get (peer);
- if (myid == mp->id)
- {
- LOG (GNUNET_ERROR_TYPE_INFO, "CONNECTED %s (self)\n", own_id);
- path = path_new (1);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_INFO, "CONNECTED %s <= %s\n",
- own_id, GNUNET_i2s (peer));
- path = path_new (2);
- path->peers[1] = mp->id;
- GNUNET_PEER_change_rc (mp->id, 1);
- GNUNET_STATISTICS_update (stats, "# peers", 1, GNUNET_NO);
- }
- path->peers[0] = myid;
- GNUNET_PEER_change_rc (myid, 1);
- GMP_add_path (mp, path, GNUNET_YES);
-
- mp->connections = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_YES);
-
- if (NULL != GMP_get_tunnel (mp) &&
- 0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, peer))
- {
- GMP_connect (mp);
- }
-
- return;
-}
-
-
-/**
- * Method called whenever a peer disconnects.
- *
- * @param cls closure
- * @param peer peer identity this notification is about
- */
-static void
-core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
-{
- struct CadetPeer *p;
- struct CadetPeerPath *direct_path;
- char own_id[16];
-
- strncpy (own_id, GNUNET_i2s (&my_full_id), 15);
- p = GNUNET_CONTAINER_multipeermap_get (peers, peer);
- if (NULL == p)
- {
- GNUNET_break (0);
- return;
- }
- if (myid == p->id)
- LOG (GNUNET_ERROR_TYPE_INFO, "DISCONNECTED %s (self)\n", own_id);
- else
- LOG (GNUNET_ERROR_TYPE_DEBUG, "DISCONNECTED %s <= %s\n",
- own_id, GNUNET_i2s (peer));
- direct_path = pop_direct_path (p);
- GNUNET_CONTAINER_multihashmap_iterate (p->connections, ¬ify_broken, p);
- GNUNET_CONTAINER_multihashmap_destroy (p->connections);
- p->connections = NULL;
- if (NULL != p->core_transmit)
- {
- GNUNET_CORE_notify_transmit_ready_cancel (p->core_transmit);
- p->core_transmit = NULL;
- }
- GNUNET_STATISTICS_update (stats, "# peers", -1, GNUNET_NO);
-
- path_destroy (direct_path);
- return;
-}
-
-
-/**
- * Functions to handle messages from core
- */
-static struct GNUNET_CORE_MessageHandler core_handlers[] = {
- {&GMC_handle_create, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, 0},
- {&GMC_handle_confirm, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK,
- sizeof (struct GNUNET_CADET_ConnectionACK)},
- {&GMC_handle_broken, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN,
- sizeof (struct GNUNET_CADET_ConnectionBroken)},
- {&GMC_handle_destroy, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY,
- sizeof (struct GNUNET_CADET_ConnectionDestroy)},
- {&GMC_handle_ack, GNUNET_MESSAGE_TYPE_CADET_ACK,
- sizeof (struct GNUNET_CADET_ACK)},
- {&GMC_handle_poll, GNUNET_MESSAGE_TYPE_CADET_POLL,
- sizeof (struct GNUNET_CADET_Poll)},
- {&GMC_handle_encrypted, GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED, 0},
- {&GMC_handle_kx, GNUNET_MESSAGE_TYPE_CADET_KX, 0},
- {NULL, 0, 0}
-};
-
-
-/**
- * To be called on core init/fail.
- *
- * @param cls Closure (config)
- * @param identity the public identity of this peer
- */
-static void
-core_init (void *cls,
- const struct GNUNET_PeerIdentity *identity)
-{
- const struct GNUNET_CONFIGURATION_Handle *c = cls;
- static int i = 0;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Core init\n");
- if (0 != memcmp (identity, &my_full_id, sizeof (my_full_id)))
- {
- LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong CORE service\n"));
- LOG (GNUNET_ERROR_TYPE_ERROR, " core id %s\n", GNUNET_i2s (identity));
- LOG (GNUNET_ERROR_TYPE_ERROR, " my id %s\n", GNUNET_i2s (&my_full_id));
- GNUNET_CORE_disconnect (core_handle);
- core_handle = GNUNET_CORE_connect (c, /* Main configuration */
- NULL, /* Closure passed to CADET
functions */
- &core_init, /* Call core_init
once connected */
- &core_connect, /* Handle connects */
- &core_disconnect, /* remove peers on
disconnects */
- NULL, /* Don't notify about all
incoming messages */
- GNUNET_NO, /* For header only in
notification */
- NULL, /* Don't notify about all
outbound messages */
- GNUNET_NO, /* For header-only out
notification */
- core_handlers); /* Register these
handlers */
- if (10 < i++)
- GNUNET_abort();
- }
- GML_start ();
- return;
-}
-
-
-/**
- * Core callback to write a pre-constructed data packet to core buffer
- *
- * @param cls Closure (CadetTransmissionDescriptor with data in "data"
member).
- * @param size Number of bytes available in buf.
- * @param buf Where the to write the message.
- *
- * @return number of bytes written to buf
- */
-static size_t
-send_core_data_raw (void *cls, size_t size, void *buf)
-{
- struct GNUNET_MessageHeader *msg = cls;
- size_t total_size;
-
- GNUNET_assert (NULL != msg);
- total_size = ntohs (msg->size);
-
- if (total_size > size)
- {
- GNUNET_break (0);
- return 0;
- }
- memcpy (buf, msg, total_size);
- GNUNET_free (cls);
- return total_size;
-}
-
-
-/**
- * Function to send a create connection message to a peer.
- *
- * @param c Connection to create.
- * @param size number of bytes available in buf
- * @param buf where the callee should write the message
- * @return number of bytes written to buf
- */
-static size_t
-send_core_connection_create (struct CadetConnection *c, size_t size, void *buf)
-{
- struct GNUNET_CADET_ConnectionCreate *msg;
- struct GNUNET_PeerIdentity *peer_ptr;
- const struct CadetPeerPath *p = GMC_get_path (c);
- size_t size_needed;
- int i;
-
- if (NULL == p)
- return 0;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending CONNECTION CREATE...\n");
- size_needed =
- sizeof (struct GNUNET_CADET_ConnectionCreate) +
- p->length * sizeof (struct GNUNET_PeerIdentity);
-
- if (size < size_needed || NULL == buf)
- {
- GNUNET_break (0);
- return 0;
- }
- msg = (struct GNUNET_CADET_ConnectionCreate *) buf;
- msg->header.size = htons (size_needed);
- msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE);
- msg->cid = *GMC_get_id (c);
-
- peer_ptr = (struct GNUNET_PeerIdentity *) &msg[1];
- for (i = 0; i < p->length; i++)
- {
- GNUNET_PEER_resolve (p->peers[i], peer_ptr++);
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "CONNECTION CREATE (%u bytes long) sent!\n",
- size_needed);
- return size_needed;
-}
-
-
-/**
- * Creates a path ack message in buf and frees all unused resources.
- *
- * @param c Connection to send an ACK on.
- * @param size number of bytes available in buf
- * @param buf where the callee should write the message
- *
- * @return number of bytes written to buf
- */
-static size_t
-send_core_connection_ack (struct CadetConnection *c, size_t size, void *buf)
-{
- struct GNUNET_CADET_ConnectionACK *msg = buf;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending CONNECTION ACK...\n");
- if (sizeof (struct GNUNET_CADET_ConnectionACK) > size)
- {
- GNUNET_break (0);
- return 0;
- }
- msg->header.size = htons (sizeof (struct GNUNET_CADET_ConnectionACK));
- msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK);
- msg->cid = *GMC_get_id (c);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "CONNECTION ACK sent!\n");
- return sizeof (struct GNUNET_CADET_ConnectionACK);
-}
-
-
-/******************************************************************************/
-/******************************** STATIC
***********************************/
-/******************************************************************************/
-
-
-/**
- * Get priority for a queued message.
- *
- * @param q Queued message
- *
- * @return CORE priority to use.
- */
-static enum GNUNET_CORE_Priority
-get_priority (struct CadetPeerQueue *q)
-{
- enum GNUNET_CORE_Priority low;
- enum GNUNET_CORE_Priority high;
-
- if (NULL == q)
- {
- GNUNET_break (0);
- return GNUNET_CORE_PRIO_BACKGROUND;
- }
-
- /* Relayed traffic has lower priority, our own traffic has higher */
- if (NULL == q->c || GNUNET_NO == GMC_is_origin (q->c, q->fwd))
- {
- low = GNUNET_CORE_PRIO_BEST_EFFORT;
- high = GNUNET_CORE_PRIO_URGENT;
- }
- else
- {
- low = GNUNET_CORE_PRIO_URGENT;
- high = GNUNET_CORE_PRIO_CRITICAL_CONTROL;
- }
-
- /* Bulky payload has lower priority, control traffic has higher. */
- if (GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED == q->type)
- return low;
- else
- return high;
-}
-
-
-/**
- * Iterator over tunnel hash map entries to destroy the tunnel during shutdown.
- *
- * @param cls closure
- * @param key current key code
- * @param value value in the hash map
- * @return #GNUNET_YES if we should continue to iterate,
- * #GNUNET_NO if not.
- */
-static int
-shutdown_tunnel (void *cls,
- const struct GNUNET_PeerIdentity *key,
- void *value)
-{
- struct CadetPeer *p = value;
- struct CadetTunnel3 *t = p->tunnel;
-
- if (NULL != t)
- GMT_destroy (t);
- return GNUNET_YES;
-}
-
-
-/**
- * Destroy the peer_info and free any allocated resources linked to it
- *
- * @param peer The peer_info to destroy.
- *
- * @return GNUNET_OK on success
- */
-static int
-peer_destroy (struct CadetPeer *peer)
-{
- struct GNUNET_PeerIdentity id;
- struct CadetPeerPath *p;
- struct CadetPeerPath *nextp;
-
- GNUNET_PEER_resolve (peer->id, &id);
- GNUNET_PEER_change_rc (peer->id, -1);
-
- LOG (GNUNET_ERROR_TYPE_WARNING, "destroying peer %s\n", GNUNET_i2s (&id));
-
- if (GNUNET_YES !=
- GNUNET_CONTAINER_multipeermap_remove (peers, &id, peer))
- {
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_WARNING, " not in peermap!!\n");
- }
- if (NULL != peer->search_h)
- {
- GMD_search_stop (peer->search_h);
- }
- p = peer->path_head;
- while (NULL != p)
- {
- nextp = p->next;
- GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, p);
- path_destroy (p);
- p = nextp;
- }
- GMT_destroy_empty (peer->tunnel);
- GNUNET_free (peer);
- return GNUNET_OK;
-}
-
-
-/**
- * Returns if peer is used (has a tunnel or is neighbor).
- *
- * @param peer Peer to check.
- *
- * @return #GNUNET_YES if peer is in use.
- */
-static int
-peer_is_used (struct CadetPeer *peer)
-{
- struct CadetPeerPath *p;
-
- if (NULL != peer->tunnel)
- return GNUNET_YES;
-
- for (p = peer->path_head; NULL != p; p = p->next)
- {
- if (p->length < 3)
- return GNUNET_YES;
- }
- return GNUNET_NO;
-}
-
-
-/**
- * Iterator over all the peers to get the oldest timestamp.
- *
- * @param cls Closure (unsued).
- * @param key ID of the peer.
- * @param value Peer_Info of the peer.
- */
-static int
-peer_get_oldest (void *cls,
- const struct GNUNET_PeerIdentity *key,
- void *value)
-{
- struct CadetPeer *p = value;
- struct GNUNET_TIME_Absolute *abs = cls;
-
- /* Don't count active peers */
- if (GNUNET_YES == peer_is_used (p))
- return GNUNET_YES;
-
- if (abs->abs_value_us < p->last_contact.abs_value_us)
- abs->abs_value_us = p->last_contact.abs_value_us;
-
- return GNUNET_YES;
-}
-
-
-/**
- * Iterator over all the peers to remove the oldest entry.
- *
- * @param cls Closure (unsued).
- * @param key ID of the peer.
- * @param value Peer_Info of the peer.
- */
-static int
-peer_timeout (void *cls,
- const struct GNUNET_PeerIdentity *key,
- void *value)
-{
- struct CadetPeer *p = value;
- struct GNUNET_TIME_Absolute *abs = cls;
-
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "peer %s timeout\n", GNUNET_i2s (key));
-
- if (p->last_contact.abs_value_us == abs->abs_value_us &&
- GNUNET_NO == peer_is_used (p))
- {
- peer_destroy (p);
- return GNUNET_NO;
- }
- return GNUNET_YES;
-}
-
-
-/**
- * Delete oldest unused peer.
- */
-static void
-peer_delete_oldest (void)
-{
- struct GNUNET_TIME_Absolute abs;
-
- abs = GNUNET_TIME_UNIT_FOREVER_ABS;
-
- GNUNET_CONTAINER_multipeermap_iterate (peers,
- &peer_get_oldest,
- &abs);
- GNUNET_CONTAINER_multipeermap_iterate (peers,
- &peer_timeout,
- &abs);
-}
-
-
-/**
- * Choose the best (yet unused) path towards a peer,
- * considering the tunnel properties.
- *
- * @param peer The destination peer.
- *
- * @return Best current known path towards the peer, if any.
- */
-static struct CadetPeerPath *
-peer_get_best_path (const struct CadetPeer *peer)
-{
- struct CadetPeerPath *best_p;
- struct CadetPeerPath *p;
- unsigned int best_cost;
- unsigned int cost;
-
- best_cost = UINT_MAX;
- best_p = NULL;
- for (p = peer->path_head; NULL != p; p = p->next)
- {
- if (GNUNET_NO == path_is_valid (p))
- continue; /* Don't use invalid paths. */
- if (GNUNET_YES == GMT_is_path_used (peer->tunnel, p))
- continue; /* If path is already in use, skip it. */
-
- if ((cost = GMT_get_path_cost (peer->tunnel, p)) < best_cost)
- {
- best_cost = cost;
- best_p = p;
- }
- }
- return best_p;
-}
-
-
-/**
- * Is this queue element sendable?
- *
- * - All management traffic is always sendable.
- * - For payload traffic, check the connection flow control.
- *
- * @param q Queue element to inspect.
- *
- * @return #GNUNET_YES if it is sendable, #GNUNET_NO otherwise.
- */
-static int
-queue_is_sendable (struct CadetPeerQueue *q)
-{
- /* Is PID-independent? */
- switch (q->type)
- {
- case GNUNET_MESSAGE_TYPE_CADET_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_POLL:
- case GNUNET_MESSAGE_TYPE_CADET_KX:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
- return GNUNET_YES;
-
- case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
- break;
-
- default:
- GNUNET_break (0);
- }
-
- return GMC_is_sendable (q->c, q->fwd);
-}
-
-
-/**
- * Get first sendable message.
- *
- * @param peer The destination peer.
- *
- * @return First transmittable message, if any. Otherwise, NULL.
- */
-static struct CadetPeerQueue *
-peer_get_first_message (const struct CadetPeer *peer)
-{
- struct CadetPeerQueue *q;
-
- for (q = peer->queue_head; NULL != q; q = q->next)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking %p towards %s\n", q, GMC_2s
(q->c));
- if (queue_is_sendable (q))
- return q;
- }
-
- return NULL;
-}
-
-
-/**
- * Function to process paths received for a new peer addition. The recorded
- * paths form the initial tunnel, which can be optimized later.
- * Called on each result obtained for the DHT search.
- *
- * @param cls closure
- * @param path
- */
-static void
-search_handler (void *cls, const struct CadetPeerPath *path)
-{
- struct CadetPeer *peer = cls;
- unsigned int connection_count;
-
- GMP_add_path_to_all (path, GNUNET_NO);
-
- /* Count connections */
- connection_count = GMT_count_connections (peer->tunnel);
-
- /* If we already have 3 (or more (?!)) connections, it's enough */
- if (3 <= connection_count)
- return;
-
- if (CADET_TUNNEL3_SEARCHING == GMT_get_cstate (peer->tunnel))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " ... connect!\n");
- GMP_connect (peer);
- }
- return;
-}
-
-
-
-/**
- * Core callback to write a queued packet to core buffer
- *
- * @param cls Closure (peer info).
- * @param size Number of bytes available in buf.
- * @param buf Where the to write the message.
- *
- * @return number of bytes written to buf
- */
-static size_t
-queue_send (void *cls, size_t size, void *buf)
-{
- struct CadetPeer *peer = cls;
- struct CadetConnection *c;
- struct CadetPeerQueue *queue;
- const struct GNUNET_PeerIdentity *dst_id;
- size_t data_size;
- uint32_t pid;
-
- pid = 0;
- peer->core_transmit = NULL;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Queue send towards %s (max %u)\n",
- GMP_2s (peer), size);
-
- if (NULL == buf || 0 == size)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Buffer size 0.\n");
- return 0;
- }
-
- /* Initialize */
- queue = peer_get_first_message (peer);
- if (NULL == queue)
- {
- GNUNET_assert (0); /* Core tmt_rdy should've been canceled */
- return 0;
- }
- c = queue->c;
-
- dst_id = GNUNET_PEER_resolve2 (peer->id);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " on connection %s %s\n",
- GMC_2s (c), GM_f2s(queue->fwd));
- /* Check if buffer size is enough for the message */
- if (queue->size > size)
- {
- LOG (GNUNET_ERROR_TYPE_WARNING, "not enough room (%u vs %u), reissue\n",
- queue->size, size);
- peer->core_transmit =
- GNUNET_CORE_notify_transmit_ready (core_handle,
- GNUNET_NO, get_priority (queue),
- GNUNET_TIME_UNIT_FOREVER_REL,
- dst_id,
- queue->size,
- &queue_send,
- peer);
- return 0;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " size %u ok\n", queue->size);
-
- /* Fill buf */
- switch (queue->type)
- {
- case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
- pid = GMC_get_pid (queue->c, queue->fwd);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " payload ID %u\n", pid);
- data_size = send_core_data_raw (queue->cls, size, buf);
- ((struct GNUNET_CADET_Encrypted *) buf)->pid = htonl (pid);
- break;
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
- case GNUNET_MESSAGE_TYPE_CADET_KX:
- case GNUNET_MESSAGE_TYPE_CADET_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_POLL:
- LOG (GNUNET_ERROR_TYPE_DEBUG, " raw %s\n", GM_m2s (queue->type));
- data_size = send_core_data_raw (queue->cls, size, buf);
- break;
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
- LOG (GNUNET_ERROR_TYPE_DEBUG, " path create\n");
- if (GMC_is_origin (c, GNUNET_YES))
- data_size = send_core_connection_create (queue->c, size, buf);
- else
- data_size = send_core_data_raw (queue->cls, size, buf);
- break;
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK:
- LOG (GNUNET_ERROR_TYPE_DEBUG, " path ack\n");
- if (GMC_is_origin (c, GNUNET_NO) ||
- GMC_is_origin (c, GNUNET_YES))
- data_size = send_core_connection_ack (queue->c, size, buf);
- else
- data_size = send_core_data_raw (queue->cls, size, buf);
- break;
- case GNUNET_MESSAGE_TYPE_CADET_DATA:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
- /* This should be encapsulted */
- GNUNET_break (0);
- data_size = 0;
- break;
- default:
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_WARNING, " type unknown: %u\n", queue->type);
- data_size = 0;
- }
-
- if (0 < drop_percent &&
- GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 101) <
drop_percent)
- {
- LOG (GNUNET_ERROR_TYPE_WARNING, "DD %s on connection %s\n",
- GM_m2s (queue->type), GMC_2s (c));
- data_size = 0;
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_INFO,
- "snd %s (%s %u) on connection %s (%p) %s (size %u)\n",
- GM_m2s (queue->type), GM_m2s (queue->payload_type),
- queue->payload_type, GMC_2s (c), c, GM_f2s (queue->fwd), data_size);
- }
-
- /* Free queue, but cls was freed by send_core_* */
- GMP_queue_destroy (queue, GNUNET_NO, GNUNET_YES, pid);
-
- /* If more data in queue, send next */
- queue = peer_get_first_message (peer);
- if (NULL != queue)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " more data!\n");
- if (NULL == peer->core_transmit)
- {
- peer->core_transmit =
- GNUNET_CORE_notify_transmit_ready (core_handle,
- GNUNET_NO, get_priority (queue),
- GNUNET_TIME_UNIT_FOREVER_REL,
- dst_id,
- queue->size,
- &queue_send,
- peer);
- queue->start_waiting = GNUNET_TIME_absolute_get ();
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "* tmt rdy called somewhere else\n");
- }
-// GMC_start_poll (); FIXME needed?
- }
- else
- {
-// GMC_stop_poll(); FIXME needed?
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " return %d\n", data_size);
- queue_debug (peer);
- return data_size;
-}
-
-
-/******************************************************************************/
-/******************************** API
***********************************/
-/******************************************************************************/
-
-
-/**
- * Free a transmission that was already queued with all resources
- * associated to the request.
- *
- * @param queue Queue handler to cancel.
- * @param clear_cls Is it necessary to free associated cls?
- * @param sent Was it really sent? (Could have been canceled)
- * @param pid PID, if relevant (was sent and was a payload message).
- */
-void
-GMP_queue_destroy (struct CadetPeerQueue *queue, int clear_cls,
- int sent, uint32_t pid)
-{
- struct CadetPeer *peer;
-
- peer = queue->peer;
-
- if (GNUNET_YES == clear_cls)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "queue destroy type %s\n",
- GM_m2s (queue->type));
- switch (queue->type)
- {
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
- LOG (GNUNET_ERROR_TYPE_INFO, "destroying a DESTROY message\n");
- /* fall through */
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
- case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE:
- case GNUNET_MESSAGE_TYPE_CADET_KX:
- case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
- case GNUNET_MESSAGE_TYPE_CADET_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_POLL:
- GNUNET_free_non_null (queue->cls);
- break;
-
- default:
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_ERROR, " type %s unknown!\n",
- GM_m2s (queue->type));
- }
- }
- GNUNET_CONTAINER_DLL_remove (peer->queue_head, peer->queue_tail, queue);
-
- if (queue->type != GNUNET_MESSAGE_TYPE_CADET_ACK &&
- queue->type != GNUNET_MESSAGE_TYPE_CADET_POLL)
- {
- peer->queue_n--;
- }
-
- if (NULL != queue->callback)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " calling callback\n");
- queue->callback (queue->callback_cls,
- queue->c, sent, queue->type, pid,
- queue->fwd, queue->size,
- GNUNET_TIME_absolute_get_duration (queue->start_waiting));
- }
-
- if (NULL == peer_get_first_message (peer) && NULL != peer->core_transmit)
- {
- GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit);
- peer->core_transmit = NULL;
- }
-
- GNUNET_free (queue);
-}
-
-
-/**
- * @brief Queue and pass message to core when possible.
- *
- * @param peer Peer towards which to queue the message.
- * @param cls Closure (@c type dependant). It will be used by queue_send to
- * build the message to be sent if not already prebuilt.
- * @param type Type of the message, 0 for a raw message.
- * @param size Size of the message.
- * @param c Connection this message belongs to (can be NULL).
- * @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!)
- * @param cont Continuation to be called once CORE has taken the message.
- * @param cont_cls Closure for @c cont.
- *
- * @return Handle to cancel the message before it is sent. Once cont is called
- * message has been sent and therefore the handle is no longer valid.
- */
-struct CadetPeerQueue *
-GMP_queue_add (struct CadetPeer *peer, void *cls, uint16_t type,
- uint16_t payload_type, uint32_t payload_id, size_t size,
- struct CadetConnection *c, int fwd,
- GMP_sent cont, void *cont_cls)
-{
- struct CadetPeerQueue *queue;
- int priority;
- int call_core;
-
- LOG (GNUNET_ERROR_TYPE_INFO,
- "que %s (%s %u) on connection %s (%p) %s towards %s (size %u)\n",
- GM_m2s (type), GM_m2s (payload_type), payload_id,
- GMC_2s (c), c, GM_f2s (fwd), GMP_2s (peer), size);
-
- if (NULL == peer->connections)
- {
- /* We are not connected to this peer, ignore request. */
- LOG (GNUNET_ERROR_TYPE_WARNING, "%s not a neighbor\n", GMP_2s (peer));
- GNUNET_STATISTICS_update (stats, "# messages dropped due to wrong hop", 1,
- GNUNET_NO);
- return NULL;
- }
-
- priority = 0;
-
- if (GNUNET_MESSAGE_TYPE_CADET_POLL == type ||
- GNUNET_MESSAGE_TYPE_CADET_ACK == type)
- {
- priority = 100;
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "priority %d\n", priority);
-
- call_core = NULL == c ? GNUNET_YES : GMC_is_sendable (c, fwd);
- queue = GNUNET_new (struct CadetPeerQueue);
- queue->cls = cls;
- queue->type = type;
- queue->payload_type = payload_type;
- queue->payload_id = payload_id;
- queue->size = size;
- queue->peer = peer;
- queue->c = c;
- queue->fwd = fwd;
- queue->callback = cont;
- queue->callback_cls = cont_cls;
- if (100 > priority)
- {
- GNUNET_CONTAINER_DLL_insert_tail (peer->queue_head, peer->queue_tail,
queue);
- peer->queue_n++;
- }
- else
- {
- GNUNET_CONTAINER_DLL_insert (peer->queue_head, peer->queue_tail, queue);
- call_core = GNUNET_YES;
- }
-
- if (NULL == peer->core_transmit && GNUNET_YES == call_core)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "calling core tmt rdy towards %s for %u bytes\n",
- GMP_2s (peer), size);
- peer->core_transmit =
- GNUNET_CORE_notify_transmit_ready (core_handle,
- GNUNET_NO, get_priority (queue),
- GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_PEER_resolve2 (peer->id),
- size,
- &queue_send,
- peer);
- queue->start_waiting = GNUNET_TIME_absolute_get ();
- }
- else if (GNUNET_NO == call_core)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "core tmt rdy towards %s not needed\n",
- GMP_2s (peer));
-
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "core tmt rdy towards %s already called\n",
- GMP_2s (peer));
-
- }
- queue_debug (peer);
- return queue;
-}
-
-
-/**
- * Cancel all queued messages to a peer that belong to a certain connection.
- *
- * @param peer Peer towards whom to cancel.
- * @param c Connection whose queued messages to cancel. Might be destroyed by
- * the sent continuation call.
- */
-void
-GMP_queue_cancel (struct CadetPeer *peer, struct CadetConnection *c)
-{
- struct CadetPeerQueue *q;
- struct CadetPeerQueue *next;
- struct CadetPeerQueue *prev;
-
- for (q = peer->queue_head; NULL != q; q = next)
- {
- prev = q->prev;
- if (q->c == c)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GMP queue cancel %s\n", GM_m2s (q->type));
- if (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY != q->type)
- {
- q->c = NULL;
- }
- else
- {
- GMP_queue_destroy (q, GNUNET_YES, GNUNET_NO, 0);
- }
-
- /* Get next from prev, q->next might be already freed:
- * queue destroy -> callback -> GMC_destroy -> cancel_queues -> here
- */
- if (NULL == prev)
- next = peer->queue_head;
- else
- next = prev->next;
- }
- else
- {
- next = q->next;
- }
- }
- if (NULL == peer->queue_head)
- {
- if (NULL != peer->core_transmit)
- {
- GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit);
- peer->core_transmit = NULL;
- }
- }
-}
-
-
-/**
- * Get the first transmittable message for a connection.
- *
- * @param peer Neighboring peer.
- * @param c Connection.
- *
- * @return First transmittable message.
- */
-static struct CadetPeerQueue *
-connection_get_first_message (struct CadetPeer *peer, struct CadetConnection
*c)
-{
- struct CadetPeerQueue *q;
-
- for (q = peer->queue_head; NULL != q; q = q->next)
- {
- if (q->c != c)
- continue;
- if (queue_is_sendable (q))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " sendable!!\n");
- return q;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " not sendable\n");
- }
-
- return NULL;
-}
-
-
-/**
- * Get the first message for a connection and unqueue it.
- *
- * @param peer Neighboring peer.
- * @param c Connection.
- *
- * @return First message for this connection.
- */
-struct GNUNET_MessageHeader *
-GMP_connection_pop (struct CadetPeer *peer, struct CadetConnection *c)
-{
- struct CadetPeerQueue *q;
- struct CadetPeerQueue *next;
- struct GNUNET_MessageHeader *msg;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection pop on %s\n", GMC_2s (c));
- for (q = peer->queue_head; NULL != q; q = next)
- {
- next = q->next;
- if (q->c != c)
- continue;
- switch (q->type)
- {
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
- case GNUNET_MESSAGE_TYPE_CADET_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_POLL:
- GMP_queue_destroy (q, GNUNET_YES, GNUNET_NO, 0);
- continue;
-
- case GNUNET_MESSAGE_TYPE_CADET_KX:
- case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
- msg = (struct GNUNET_MessageHeader *) q->cls;
- GMP_queue_destroy (q, GNUNET_NO, GNUNET_NO, 0);
- return msg;
-
- default:
- GNUNET_break (0);
- }
- }
-
- return NULL;
-}
-
-
-void
-GMP_queue_unlock (struct CadetPeer *peer, struct CadetConnection *c)
-{
- struct CadetPeerQueue *q;
- size_t size;
-
- if (NULL != peer->core_transmit)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " already unlocked!\n");
- return; /* Already unlocked */
- }
-
- q = connection_get_first_message (peer, c);
- if (NULL == q)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " queue empty!\n");
- return; /* Nothing to transmit */
- }
-
- size = q->size;
- peer->core_transmit =
- GNUNET_CORE_notify_transmit_ready (core_handle,
- GNUNET_NO, get_priority (q),
- GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_PEER_resolve2 (peer->id),
- size,
- &queue_send,
- peer);
-}
-
-
-/**
- * Initialize the peer subsystem.
- *
- * @param c Configuration.
- */
-void
-GMP_init (const struct GNUNET_CONFIGURATION_Handle *c)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
- peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_PEERS",
- &max_peers))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
- "CADET", "MAX_PEERS", "USING DEFAULT");
- max_peers = 1000;
- }
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (c, "CADET", "DROP_PERCENT",
- &drop_percent))
- {
- drop_percent = 0;
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
"**************************************\n");
- LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n");
- LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n");
- LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n");
- LOG (GNUNET_ERROR_TYPE_WARNING,
"**************************************\n");
- }
-
- core_handle = GNUNET_CORE_connect (c, /* Main configuration */
- NULL, /* Closure passed to CADET
functions */
- &core_init, /* Call core_init once
connected */
- &core_connect, /* Handle connects */
- &core_disconnect, /* remove peers on
disconnects */
- NULL, /* Don't notify about all
incoming messages */
- GNUNET_NO, /* For header only in
notification */
- NULL, /* Don't notify about all
outbound messages */
- GNUNET_NO, /* For header-only out
notification */
- core_handlers); /* Register these
handlers */
- if (GNUNET_YES !=
- GNUNET_CONFIGURATION_get_value_yesno (c, "CADET", "DISABLE_TRY_CONNECT"))
- {
- transport_handle = GNUNET_TRANSPORT_connect (c, &my_full_id, NULL, /* cls
*/
- /* Notify callbacks */
- NULL, NULL, NULL);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
"**************************************\n");
- LOG (GNUNET_ERROR_TYPE_WARNING, "* DISABLE TRYING CONNECT in config
*\n");
- LOG (GNUNET_ERROR_TYPE_WARNING, "* Use this only for test purposes.
*\n");
- LOG (GNUNET_ERROR_TYPE_WARNING,
"**************************************\n");
- transport_handle = NULL;
- }
-
-
-
- if (NULL == core_handle)
- {
- GNUNET_break (0);
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
-
-}
-
-/**
- * Shut down the peer subsystem.
- */
-void
-GMP_shutdown (void)
-{
- GNUNET_CONTAINER_multipeermap_iterate (peers, &shutdown_tunnel, NULL);
-
- if (core_handle != NULL)
- {
- GNUNET_CORE_disconnect (core_handle);
- core_handle = NULL;
- }
- if (transport_handle != NULL)
- {
- GNUNET_TRANSPORT_disconnect (transport_handle);
- transport_handle = NULL;
- }
- GNUNET_PEER_change_rc (myid, -1);
-}
-
-/**
- * Retrieve the CadetPeer stucture associated with the peer, create one
- * and insert it in the appropriate structures if the peer is not known yet.
- *
- * @param peer_id Full identity of the peer.
- *
- * @return Existing or newly created peer structure.
- */
-struct CadetPeer *
-GMP_get (const struct GNUNET_PeerIdentity *peer_id)
-{
- struct CadetPeer *peer;
-
- peer = GNUNET_CONTAINER_multipeermap_get (peers, peer_id);
- if (NULL == peer)
- {
- peer = GNUNET_new (struct CadetPeer);
- if (GNUNET_CONTAINER_multipeermap_size (peers) > max_peers)
- {
- peer_delete_oldest ();
- }
- GNUNET_CONTAINER_multipeermap_put (peers, peer_id, peer,
-
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
- peer->id = GNUNET_PEER_intern (peer_id);
- }
- peer->last_contact = GNUNET_TIME_absolute_get();
-
- return peer;
-}
-
-
-/**
- * Retrieve the CadetPeer stucture associated with the peer, create one
- * and insert it in the appropriate structures if the peer is not known yet.
- *
- * @param peer Short identity of the peer.
- *
- * @return Existing or newly created peer structure.
- */
-struct CadetPeer *
-GMP_get_short (const GNUNET_PEER_Id peer)
-{
- return GMP_get (GNUNET_PEER_resolve2 (peer));
-}
-
-
-/**
- * Try to connect to a peer on transport level.
- *
- * @param cls Closure (peer).
- * @param tc TaskContext.
- */
-static void
-try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct CadetPeer *peer = cls;
-
- if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
- return;
-
- GNUNET_TRANSPORT_try_connect (transport_handle,
- GNUNET_PEER_resolve2 (peer->id), NULL, NULL);
-}
-
-
-/**
- * Try to establish a new connection to this peer (in its tunnel).
- * If the peer doesn't have any path to it yet, try to get one.
- * If the peer already has some path, send a CREATE CONNECTION towards it.
- *
- * @param peer Peer to connect to.
- */
-void
-GMP_connect (struct CadetPeer *peer)
-{
- struct CadetTunnel3 *t;
- struct CadetPeerPath *p;
- struct CadetConnection *c;
- int rerun_search;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "peer_connect towards %s\n", GMP_2s (peer));
-
- /* If we have a current hello, try to connect using it. */
- GMP_try_connect (peer);
-
- t = peer->tunnel;
- c = NULL;
- rerun_search = GNUNET_NO;
-
- if (NULL != peer->path_head)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " some path exists\n");
- p = peer_get_best_path (peer);
- if (NULL != p)
- {
- char *s;
-
- s = path_2s (p);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " path to use: %s\n", s);
- GNUNET_free (s);
-
- c = GMT_use_path (t, p);
- if (NULL == c)
- {
- /* This case can happen when the path includes a first hop that is
- * not yet known to be connected.
- *
- * This happens quite often during testing when running cadet
- * under valgrind: core connect notifications come very late and the
- * DHT result has already come and created a valid path.
- * In this case, the peer->connections hashmap will be NULL and
- * tunnel_use_path will not be able to create a connection from that
- * path.
- *
- * Re-running the DHT GET should give core time to callback.
- *
- * GMT_use_path -> GMC_new -> register_neighbors takes care of
- * updating statistics about this issue.
- */
- rerun_search = GNUNET_YES;
- }
- else
- {
- GMC_send_create (c);
- return;
- }
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " but is NULL, all paths are in use\n");
- }
- }
-
- if (NULL != peer->search_h && GNUNET_YES == rerun_search)
- {
- GMD_search_stop (peer->search_h);
- peer->search_h = NULL;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " Stopping DHT GET for peer %s\n",
- GMP_2s (peer));
- }
-
- if (NULL == peer->search_h)
- {
- const struct GNUNET_PeerIdentity *id;
-
- id = GNUNET_PEER_resolve2 (peer->id);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " Starting DHT GET for peer %s\n", GMP_2s (peer));
- peer->search_h = GMD_search (id, &search_handler, peer);
- if (CADET_TUNNEL3_NEW == GMT_get_cstate (t))
- GMT_change_cstate (t, CADET_TUNNEL3_SEARCHING);
- }
-}
-
-
-/**
- * Chech whether there is a direct (core level) connection to peer.
- *
- * @param peer Peer to check.
- *
- * @return #GNUNET_YES if there is a direct connection.
- */
-int
-GMP_is_neighbor (const struct CadetPeer *peer)
-{
- struct CadetPeerPath *path;
-
- if (NULL == peer->connections)
- return GNUNET_NO;
-
- for (path = peer->path_head; NULL != path; path = path->next)
- {
- if (3 > path->length)
- return GNUNET_YES;
- }
-
- /* Is not a neighbor but connections is not NULL, probably disconnecting */
- return GNUNET_NO;
-}
-
-
-/**
- * Create and initialize a new tunnel towards a peer, in case it has none.
- * In case the peer already has a tunnel, nothing is done.
- *
- * Does not generate any traffic, just creates the local data structures.
- *
- * @param peer Peer towards which to create the tunnel.
- */
-void
-GMP_add_tunnel (struct CadetPeer *peer)
-{
- if (NULL != peer->tunnel)
- return;
- peer->tunnel = GMT_new (peer);
-}
-
-
-/**
- * Add a connection to a neighboring peer.
- *
- * Store that the peer is the first hop of the connection in one
- * direction and that on peer disconnect the connection must be
- * notified and destroyed, for it will no longer be valid.
- *
- * @param peer Peer to add connection to.
- * @param c Connection to add.
- *
- * @return GNUNET_OK on success.
- */
-int
-GMP_add_connection (struct CadetPeer *peer,
- struct CadetConnection *c)
-{
- int result;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "adding connection %s\n", GMC_2s (c));
- LOG (GNUNET_ERROR_TYPE_DEBUG, "to peer %s\n", GMP_2s (peer));
-
- if (NULL == peer->connections)
- {
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Peer %s is not a neighbor!\n",
- GMP_2s (peer));
- return GNUNET_SYSERR;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "peer %s ok, has %u connections.\n",
- GMP_2s (peer), GNUNET_CONTAINER_multihashmap_size (peer->connections));
- result = GNUNET_CONTAINER_multihashmap_put (peer->connections,
- GMC_get_h (c),
- c,
-
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " now has %u connections.\n",
- GNUNET_CONTAINER_multihashmap_size (peer->connections));
- LOG (GNUNET_ERROR_TYPE_DEBUG, "result %u\n", result);
-
- return result;
-}
-
-
-/**
- * Add the path to the peer and update the path used to reach it in case this
- * is the shortest.
- *
- * @param peer Destination peer to add the path to.
- * @param path New path to add. Last peer must be the peer in arg 1.
- * Path will be either used of freed if already known.
- * @param trusted Do we trust that this path is real?
- *
- * @return path if path was taken, pointer to existing duplicate if exists
- * NULL on error.
- */
-struct CadetPeerPath *
-GMP_add_path (struct CadetPeer *peer, struct CadetPeerPath *path,
- int trusted)
-{
- struct CadetPeerPath *aux;
- unsigned int l;
- unsigned int l2;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "adding path [%u] to peer %s\n",
- path->length, GMP_2s (peer));
-
- if ((NULL == peer) || (NULL == path))
- {
- GNUNET_break (0);
- path_destroy (path);
- return NULL;
- }
- if (path->peers[path->length - 1] != peer->id)
- {
- GNUNET_break (0);
- path_destroy (path);
- return NULL;
- }
-
- for (l = 1; l < path->length; l++)
- {
- if (path->peers[l] == myid)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " shortening path by %u\n", l);
- for (l2 = 0; l2 < path->length - l; l2++)
- {
- path->peers[l2] = path->peers[l + l2];
- }
- path->length -= l;
- l = 1;
- path->peers = GNUNET_realloc (path->peers,
- path->length * sizeof (GNUNET_PEER_Id));
- }
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " final length: %u\n", path->length);
-
- if (2 >= path->length && GNUNET_NO == trusted)
- {
- /* Only allow CORE to tell us about direct paths */
- path_destroy (path);
- return NULL;
- }
-
- l = path_get_length (path);
- if (0 == l)
- {
- path_destroy (path);
- return NULL;
- }
-
- GNUNET_assert (peer->id == path->peers[path->length - 1]);
- for (aux = peer->path_head; aux != NULL; aux = aux->next)
- {
- l2 = path_get_length (aux);
- if (l2 > l)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " added\n");
- GNUNET_CONTAINER_DLL_insert_before (peer->path_head,
- peer->path_tail, aux, path);
- if (NULL != peer->tunnel && 3 < GMT_count_connections (peer->tunnel))
- {
- GMP_connect (peer);
- }
- return path;
- }
- else
- {
- if (l2 == l && memcmp (path->peers, aux->peers, l) == 0)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " already known\n");
- path_destroy (path);
- return aux;
- }
- }
- }
- GNUNET_CONTAINER_DLL_insert_tail (peer->path_head, peer->path_tail,
- path);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " added last\n");
- if (NULL != peer->tunnel && 3 < GMT_count_connections (peer->tunnel))
- {
- GMP_connect (peer);
- }
- return path;
-}
-
-
-/**
- * Add the path to the origin peer and update the path used to reach it in case
- * this is the shortest.
- * The path is given in peer_info -> destination, therefore we turn the path
- * upside down first.
- *
- * @param peer Peer to add the path to, being the origin of the path.
- * @param path New path to add after being inversed.
- * Path will be either used or freed.
- * @param trusted Do we trust that this path is real?
- *
- * @return path if path was taken, pointer to existing duplicate if exists
- * NULL on error.
- */
-struct CadetPeerPath *
-GMP_add_path_to_origin (struct CadetPeer *peer,
- struct CadetPeerPath *path,
- int trusted)
-{
- if (NULL == path)
- return NULL;
- path_invert (path);
- return GMP_add_path (peer, path, trusted);
-}
-
-
-/**
- * Adds a path to the info of all the peers in the path
- *
- * @param p Path to process.
- * @param confirmed Whether we know if the path works or not.
- */
-void
-GMP_add_path_to_all (const struct CadetPeerPath *p, int confirmed)
-{
- unsigned int i;
-
- /* TODO: invert and add */
- for (i = 0; i < p->length && p->peers[i] != myid; i++) /* skip'em */ ;
- for (i++; i < p->length; i++)
- {
- struct CadetPeer *aux;
- struct CadetPeerPath *copy;
-
- aux = GMP_get_short (p->peers[i]);
- copy = path_duplicate (p);
- copy->length = i + 1;
- GMP_add_path (aux, copy, p->length < 3 ? GNUNET_NO : confirmed);
- }
-}
-
-
-/**
- * Remove any path to the peer that has the extact same peers as the one given.
- *
- * @param peer Peer to remove the path from.
- * @param path Path to remove. Is always destroyed .
- */
-void
-GMP_remove_path (struct CadetPeer *peer, struct CadetPeerPath *path)
-{
- struct CadetPeerPath *iter;
- struct CadetPeerPath *next;
-
- GNUNET_assert (myid == path->peers[0]);
- GNUNET_assert (peer->id == path->peers[path->length - 1]);
-
- for (iter = peer->path_head; NULL != iter; iter = next)
- {
- next = iter->next;
- if (0 == memcmp (path->peers, iter->peers,
- sizeof (GNUNET_PEER_Id) * path->length))
- {
- GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, iter);
- if (iter != path)
- path_destroy (iter);
- }
- }
- path_destroy (path);
-}
-
-
-/**
- * Remove a connection from a neighboring peer.
- *
- * @param peer Peer to remove connection from.
- * @param c Connection to remove.
- *
- * @return GNUNET_OK on success.
- */
-int
-GMP_remove_connection (struct CadetPeer *peer,
- const struct CadetConnection *c)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "removing connection %s\n", GMC_2s (c));
- LOG (GNUNET_ERROR_TYPE_DEBUG, "from peer %s\n", GMP_2s (peer));
-
- if (NULL == peer || NULL == peer->connections)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Peer %s is not a neighbor!\n",
- GMP_2s (peer));
- return GNUNET_SYSERR;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "peer %s ok, has %u connections.\n",
- GMP_2s (peer), GNUNET_CONTAINER_multihashmap_size (peer->connections));
-
- return GNUNET_CONTAINER_multihashmap_remove (peer->connections,
- GMC_get_h (c),
- c);
-}
-
-/**
- * Start the DHT search for new paths towards the peer: we don't have
- * enough good connections.
- *
- * @param peer Destination peer.
- */
-void
-GMP_start_search (struct CadetPeer *peer)
-{
- if (NULL != peer->search_h)
- {
- GNUNET_break (0);
- return;
- }
-
- peer->search_h = GMD_search (GMP_get_id (peer), &search_handler, peer);
-}
-
-
-/**
- * Stop the DHT search for new paths towards the peer: we already have
- * enough good connections.
- *
- * @param peer Destination peer.
- */
-void
-GMP_stop_search (struct CadetPeer *peer)
-{
- if (NULL == peer->search_h)
- {
- return;
- }
-
- GMD_search_stop (peer->search_h);
- peer->search_h = NULL;
-}
-
-
-/**
- * Get the Full ID of a peer.
- *
- * @param peer Peer to get from.
- *
- * @return Full ID of peer.
- */
-const struct GNUNET_PeerIdentity *
-GMP_get_id (const struct CadetPeer *peer)
-{
- return GNUNET_PEER_resolve2 (peer->id);
-}
-
-
-/**
- * Get the Short ID of a peer.
- *
- * @param peer Peer to get from.
- *
- * @return Short ID of peer.
- */
-GNUNET_PEER_Id
-GMP_get_short_id (const struct CadetPeer *peer)
-{
- return peer->id;
-}
-
-
-/**
- * Set tunnel.
- *
- * @param peer Peer.
- * @param t Tunnel.
- */
-void
-GMP_set_tunnel (struct CadetPeer *peer, struct CadetTunnel3 *t)
-{
- peer->tunnel = t;
- if (NULL == t && NULL != peer->search_h)
- {
- GMP_stop_search (peer);
- }
-}
-
-
-/**
- * Get the tunnel towards a peer.
- *
- * @param peer Peer to get from.
- *
- * @return Tunnel towards peer.
- */
-struct CadetTunnel3 *
-GMP_get_tunnel (const struct CadetPeer *peer)
-{
- return peer->tunnel;
-}
-
-
-/**
- * Set the hello message.
- *
- * @param peer Peer whose message to set.
- * @param hello Hello message.
- */
-void
-GMP_set_hello (struct CadetPeer *peer, const struct GNUNET_HELLO_Message
*hello)
-{
- struct GNUNET_HELLO_Message *old;
- size_t size;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "set hello for %s\n", GMP_2s (peer));
- if (NULL == hello)
- return;
-
- old = GMP_get_hello (peer);
- if (NULL == old)
- {
- size = GNUNET_HELLO_size (hello);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " new (%u bytes)\n", size);
- peer->hello = GNUNET_malloc (size);
- memcpy (peer->hello, hello, size);
- }
- else
- {
- peer->hello = GNUNET_HELLO_merge (old, hello);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " merge into %p (%u bytes)\n",
- peer->hello, GNUNET_HELLO_size (hello));
- GNUNET_free (old);
- }
-}
-
-
-/**
- * Get the hello message.
- *
- * @param peer Peer whose message to get.
- *
- * @return Hello message.
- */
-struct GNUNET_HELLO_Message *
-GMP_get_hello (struct CadetPeer *peer)
-{
- struct GNUNET_TIME_Absolute expiration;
- struct GNUNET_TIME_Relative remaining;
-
- if (NULL == peer->hello)
- return NULL;
-
- expiration = GNUNET_HELLO_get_last_expiration (peer->hello);
- remaining = GNUNET_TIME_absolute_get_remaining (expiration);
- if (0 == remaining.rel_value_us)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " get - hello expired on %s\n",
- GNUNET_STRINGS_absolute_time_to_string (expiration));
- GNUNET_free (peer->hello);
- peer->hello = NULL;
- }
- return peer->hello;
-}
-
-
-/**
- * Try to connect to a peer on TRANSPORT level.
- *
- * @param peer Peer to whom to connect.
- */
-void
-GMP_try_connect (struct CadetPeer *peer)
-{
- struct GNUNET_HELLO_Message *hello;
- struct GNUNET_MessageHeader *mh;
-
- if (NULL == transport_handle)
- return;
-
- hello = GMP_get_hello (peer);
- if (NULL == hello)
- return;
-
- mh = GNUNET_HELLO_get_header (hello);
- GNUNET_TRANSPORT_offer_hello (transport_handle, mh, try_connect, peer);
-}
-
-
-/**
- * Notify a peer that a link between two other peers is broken. If any path
- * used that link, eliminate it.
- *
- * @param peer Peer affected by the change.
- * @param peer1 Peer whose link is broken.
- * @param peer2 Peer whose link is broken.
- */
-void
-GMP_notify_broken_link (struct CadetPeer *peer,
- struct GNUNET_PeerIdentity *peer1,
- struct GNUNET_PeerIdentity *peer2)
-{
- struct CadetPeerPath *iter;
- struct CadetPeerPath *next;
- unsigned int i;
- GNUNET_PEER_Id p1;
- GNUNET_PEER_Id p2;
-
- p1 = GNUNET_PEER_search (peer1);
- p2 = GNUNET_PEER_search (peer2);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Link %u-%u broken\n", p1, p2);
- if (0 == p1 || 0 == p2)
- {
- /* We don't even know them */
- return;
- }
-
- for (iter = peer->path_head; NULL != iter; iter = next)
- {
- next = iter->next;
- for (i = 0; i < iter->length - 1; i++)
- {
- if ((iter->peers[i] == p1 && iter->peers[i + 1] == p2)
- || (iter->peers[i] == p2 && iter->peers[i + 1] == p1))
- {
- char *s;
-
- s = path_2s (iter);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " - invalidating %s\n", s);
- GNUNET_free (s);
-
- path_invalidate (iter);
- }
- }
- }
-}
-
-
-/**
- * Count the number of known paths toward the peer.
- *
- * @param peer Peer to get path info.
- *
- * @return Number of known paths.
- */
-unsigned int
-GMP_count_paths (const struct CadetPeer *peer)
-{
- struct CadetPeerPath *iter;
- unsigned int i;
-
- for (iter = peer->path_head, i = 0; NULL != iter; iter = iter->next)
- i++;
-
- return i;
-}
-
-
-/**
- * Iterate all known peers.
- *
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GMP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls)
-{
- GNUNET_CONTAINER_multipeermap_iterate (peers, iter, cls);
-}
-
-
-/**
- * Get the static string for a peer ID.
- *
- * @param peer Peer.
- *
- * @return Static string for it's ID.
- */
-const char *
-GMP_2s (const struct CadetPeer *peer)
-{
- if (NULL == peer)
- return "(NULL)";
- return GNUNET_i2s (GNUNET_PEER_resolve2 (peer->id));
-}
Deleted: gnunet/src/mesh/gnunet-service-cadet_peer.h
===================================================================
--- gnunet/src/mesh/gnunet-service-cadet_peer.h 2014-05-07 12:07:02 UTC (rev
33185)
+++ gnunet/src/mesh/gnunet-service-cadet_peer.h 2014-05-07 12:07:16 UTC (rev
33186)
@@ -1,418 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2013 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_peer.h
- * @brief cadet service; dealing with remote peers
- * @author Bartlomiej Polot
- *
- * All functions in this file should use the prefix GMP (Gnunet Cadet Peer)
- */
-
-#ifndef GNUNET_SERVICE_CADET_PEER_H
-#define GNUNET_SERVICE_CADET_PEER_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0 /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-/**
- * Struct containing all information regarding a given peer
- */
-struct CadetPeer;
-
-/**
- * Struct containing info about a queued transmission to this peer
- */
-struct CadetPeerQueue;
-
-#include "gnunet-service-cadet_connection.h"
-
-/**
- * Callback called when a queued message is sent.
- *
- * @param cls Closure.
- * @param c Connection this message was on.
- * @param sent Was it really sent? (Could have been canceled)
- * @param type Type of message sent.
- * @param pid Packet ID, or 0 if not applicable (create, destroy, etc).
- * @param fwd Was this a FWD going message?
- * @param size Size of the message.
- * @param wait Time spent waiting for core (only the time for THIS message)
- */
-typedef void (*GMP_sent) (void *cls,
- struct CadetConnection *c, int sent,
- uint16_t type, uint32_t pid, int fwd, size_t size,
- struct GNUNET_TIME_Relative wait);
-
-/******************************************************************************/
-/******************************** API
***********************************/
-/******************************************************************************/
-
-/**
- * Initialize peer subsystem.
- *
- * @param c Configuration.
- */
-void
-GMP_init (const struct GNUNET_CONFIGURATION_Handle *c);
-
-/**
- * Shut down the peer subsystem.
- */
-void
-GMP_shutdown (void);
-
-
-/**
- * Retrieve the CadetPeer stucture associated with the peer, create one
- * and insert it in the appropriate structures if the peer is not known yet.
- *
- * @param peer_id Full identity of the peer.
- *
- * @return Existing or newly created peer structure.
- */
-struct CadetPeer *
-GMP_get (const struct GNUNET_PeerIdentity *peer_id);
-
-
-/**
- * Retrieve the CadetPeer stucture associated with the peer, create one
- * and insert it in the appropriate structures if the peer is not known yet.
- *
- * @param peer Short identity of the peer.
- *
- * @return Existing or newly created peer structure.
- */
-struct CadetPeer *
-GMP_get_short (const GNUNET_PEER_Id peer);
-
-/**
- * Try to establish a new connection to this peer (in its tunnel).
- * If the peer doesn't have any path to it yet, try to get one.
- * If the peer already has some path, send a CREATE CONNECTION towards it.
- *
- * @param peer Peer to connect to.
- */
-void
-GMP_connect (struct CadetPeer *peer);
-
-/**
- * Free a transmission that was already queued with all resources
- * associated to the request.
- *
- * @param queue Queue handler to cancel.
- * @param clear_cls Is it necessary to free associated cls?
- * @param sent Was it really sent? (Could have been canceled)
- * @param pid PID, if relevant (was sent and was a payload message).
- */
-void
-GMP_queue_destroy (struct CadetPeerQueue *queue, int clear_cls,
- int sent, uint32_t pid);
-
-/**
- * @brief Queue and pass message to core when possible.
- *
- * @param peer Peer towards which to queue the message.
- * @param cls Closure (@c type dependant). It will be used by queue_send to
- * build the message to be sent if not already prebuilt.
- * @param type Type of the message, 0 for a raw message.
- * @param size Size of the message.
- * @param c Connection this message belongs to (cannot be NULL).
- * @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!)
- * @param cont Continuation to be called once CORE has taken the message.
- * @param cont_cls Closure for @c cont.
- *
- * @return Handle to cancel the message before it is sent. Once cont is called
- * message has been sent and therefore the handle is no longer valid.
- */
-struct CadetPeerQueue *
-GMP_queue_add (struct CadetPeer *peer, void *cls, uint16_t type,
- uint16_t payload_type, uint32_t payload_id,
- size_t size, struct CadetConnection *c, int fwd,
- GMP_sent cont, void *cont_cls);
-
-/**
- * Cancel all queued messages to a peer that belong to a certain connection.
- *
- * @param peer Peer towards whom to cancel.
- * @param c Connection whose queued messages to cancel. Might be destroyed by
- * the sent continuation call.
- */
-void
-GMP_queue_cancel (struct CadetPeer *peer, struct CadetConnection *c);
-
-/**
- * Get the first message for a connection and unqueue it.
- *
- * @param peer Neighboring peer.
- * @param c Connection.
- *
- * @return First message for this connection.
- */
-struct GNUNET_MessageHeader *
-GMP_connection_pop (struct CadetPeer *peer, struct CadetConnection *c);
-
-void
-GMP_queue_unlock (struct CadetPeer *peer, struct CadetConnection *c);
-
-/**
- * Set tunnel.
- *
- * @param peer Peer.
- * @param t Tunnel.
- */
-void
-GMP_set_tunnel (struct CadetPeer *peer, struct CadetTunnel3 *t);
-
-/**
- * Check whether there is a direct (core level) connection to peer.
- *
- * @param peer Peer to check.
- *
- * @return #GNUNET_YES if there is a direct connection.
- */
-int
-GMP_is_neighbor (const struct CadetPeer *peer);
-
-/**
- * Create and initialize a new tunnel towards a peer, in case it has none.
- *
- * Does not generate any traffic, just creates the local data structures.
- *
- * @param peer Peer towards which to create the tunnel.
- */
-void
-GMP_add_tunnel (struct CadetPeer *peer);
-
-/**
- * Add a connection to a neighboring peer.
- *
- * Store that the peer is the first hop of the connection in one
- * direction and that on peer disconnect the connection must be
- * notified and destroyed, for it will no longer be valid.
- *
- * @param peer Peer to add connection to.
- * @param c Connection to add.
- *
- * @return GNUNET_OK on success.
- */
-int
-GMP_add_connection (struct CadetPeer *peer, struct CadetConnection *c);
-
-/**
- * Add the path to the peer and update the path used to reach it in case this
- * is the shortest.
- *
- * @param peer Destination peer to add the path to.
- * @param path New path to add. Last peer must be the peer in arg 1.
- * Path will be either used of freed if already known.
- * @param trusted Do we trust that this path is real?
- *
- * @return path if path was taken, pointer to existing duplicate if exists
- * NULL on error.
- */
-struct CadetPeerPath *
-GMP_add_path (struct CadetPeer *peer, struct CadetPeerPath *p, int trusted);
-
-/**
- * Add the path to the origin peer and update the path used to reach it in case
- * this is the shortest.
- * The path is given in peer_info -> destination, therefore we turn the path
- * upside down first.
- *
- * @param peer Peer to add the path to, being the origin of the path.
- * @param path New path to add after being inversed.
- * Path will be either used or freed.
- * @param trusted Do we trust that this path is real?
- *
- * @return path if path was taken, pointer to existing duplicate if exists
- * NULL on error.
- */
-struct CadetPeerPath *
-GMP_add_path_to_origin (struct CadetPeer *peer,
- struct CadetPeerPath *path,
- int trusted);
-
-/**
- * Adds a path to the info of all the peers in the path
- *
- * @param p Path to process.
- * @param confirmed Whether we know if the path works or not.
- */
-void
-GMP_add_path_to_all (const struct CadetPeerPath *p, int confirmed);
-
-/**
- * Remove any path to the peer that has the extact same peers as the one given.
- *
- * @param peer Peer to remove the path from.
- * @param path Path to remove. Is always destroyed .
- */
-void
-GMP_remove_path (struct CadetPeer *peer, struct CadetPeerPath *path);
-
-/**
- * Remove a connection from a neighboring peer.
- *
- * @param peer Peer to remove connection from.
- * @param c Connection to remove.
- *
- * @return GNUNET_OK on success.
- */
-int
-GMP_remove_connection (struct CadetPeer *peer, const struct CadetConnection
*c);
-
-/**
- * Start the DHT search for new paths towards the peer: we don't have
- * enough good connections.
- *
- * @param peer Destination peer.
- */
-void
-GMP_start_search (struct CadetPeer *peer);
-
-/**
- * Stop the DHT search for new paths towards the peer: we already have
- * enough good connections.
- *
- * @param peer Destination peer.
- */
-void
-GMP_stop_search (struct CadetPeer *peer);
-
-/**
- * Get the Full ID of a peer.
- *
- * @param peer Peer to get from.
- *
- * @return Full ID of peer.
- */
-const struct GNUNET_PeerIdentity *
-GMP_get_id (const struct CadetPeer *peer);
-
-/**
- * Get the Short ID of a peer.
- *
- * @param peer Peer to get from.
- *
- * @return Short ID of peer.
- */
-GNUNET_PEER_Id
-GMP_get_short_id (const struct CadetPeer *peer);
-
-/**
- * Get the tunnel towards a peer.
- *
- * @param peer Peer to get from.
- *
- * @return Tunnel towards peer.
- */
-struct CadetTunnel3 *
-GMP_get_tunnel (const struct CadetPeer *peer);
-
-/**
- * Set the hello message.
- *
- * @param peer Peer whose message to set.
- * @param hello Hello message.
- */
-void
-GMP_set_hello (struct CadetPeer *peer, const struct GNUNET_HELLO_Message
*hello);
-
-/**
- * Get the hello message.
- *
- * @param peer Peer whose message to get.
- *
- * @return Hello message.
- */
-struct GNUNET_HELLO_Message *
-GMP_get_hello (struct CadetPeer *peer);
-
-
-/**
- * Try to connect to a peer on TRANSPORT level.
- *
- * @param peer Peer to whom to connect.
- */
-void
-GMP_try_connect (struct CadetPeer *peer);
-
-/**
- * Notify a peer that a link between two other peers is broken. If any path
- * used that link, eliminate it.
- *
- * @param peer Peer affected by the change.
- * @param peer1 Peer whose link is broken.
- * @param peer2 Peer whose link is broken.
- */
-void
-GMP_notify_broken_link (struct CadetPeer *peer,
- struct GNUNET_PeerIdentity *peer1,
- struct GNUNET_PeerIdentity *peer2);
-
-/**
- * Count the number of known paths toward the peer.
- *
- * @param peer Peer to get path info.
- *
- * @return Number of known paths.
- */
-unsigned int
-GMP_count_paths (const struct CadetPeer *peer);
-
-/**
- * Iterate all known peers.
- *
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GMP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls);
-
-/**
- * Get the static string for a peer ID.
- *
- * @param peer Peer.
- *
- * @return Static string for it's ID.
- */
-const char *
-GMP_2s (const struct CadetPeer *peer);
-
-
-#if 0 /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_CADET_SERVICE_PEER_H */
-#endif
-/* end of gnunet-cadet-service_peer.h */
Deleted: gnunet/src/mesh/gnunet-service-cadet_tunnel.c
===================================================================
--- gnunet/src/mesh/gnunet-service-cadet_tunnel.c 2014-05-07 12:07:02 UTC
(rev 33185)
+++ gnunet/src/mesh/gnunet-service-cadet_tunnel.c 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -1,2887 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2013 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#include "gnunet_signatures.h"
-#include "gnunet_statistics_service.h"
-
-#include "cadet_protocol.h"
-#include "cadet_path.h"
-
-#include "gnunet-service-cadet_tunnel.h"
-#include "gnunet-service-cadet_connection.h"
-#include "gnunet-service-cadet_channel.h"
-#include "gnunet-service-cadet_peer.h"
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__)
-
-#define REKEY_WAIT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5)
-
-#define CONNECTIONS_PER_TUNNEL 3
-
-/******************************************************************************/
-/******************************** STRUCTS
**********************************/
-/******************************************************************************/
-
-struct CadetTChannel
-{
- struct CadetTChannel *next;
- struct CadetTChannel *prev;
- struct CadetChannel *ch;
-};
-
-
-/**
- * Connection list and metadata.
- */
-struct CadetTConnection
-{
- /**
- * Next in DLL.
- */
- struct CadetTConnection *next;
-
- /**
- * Prev in DLL.
- */
- struct CadetTConnection *prev;
-
- /**
- * Connection handle.
- */
- struct CadetConnection *c;
-
- /**
- * Creation time, to keep oldest connection alive.
- */
- struct GNUNET_TIME_Absolute created;
-
- /**
- * Connection throughput, to keep fastest connection alive.
- */
- uint32_t throughput;
-};
-
-/**
- * Structure used during a Key eXchange.
- */
-struct CadetTunnelKXCtx
-{
- /**
- * Decryption ("their") old key, for decrypting traffic sent by the
- * other end before the key exchange started.
- */
- struct GNUNET_CRYPTO_SymmetricSessionKey d_key_old;
-
- /**
- * Challenge to send in a ping and expect in the pong.
- */
- uint32_t challenge;
-};
-
-/**
- * Struct containing all information regarding a tunnel to a peer.
- */
-struct CadetTunnel3
-{
- /**
- * Endpoint of the tunnel.
- */
- struct CadetPeer *peer;
-
- /**
- * State of the tunnel connectivity.
- */
- enum CadetTunnel3CState cstate;
-
- /**
- * State of the tunnel encryption.
- */
- enum CadetTunnel3EState estate;
-
- /**
- * Key eXchange context.
- */
- struct CadetTunnelKXCtx *kx_ctx;
-
- /**
- * Encryption ("our") key.
- */
- struct GNUNET_CRYPTO_SymmetricSessionKey e_key;
-
- /**
- * Decryption ("their") key.
- */
- struct GNUNET_CRYPTO_SymmetricSessionKey d_key;
-
- /**
- * Task to start the rekey process.
- */
- GNUNET_SCHEDULER_TaskIdentifier rekey_task;
-
- /**
- * Paths that are actively used to reach the destination peer.
- */
- struct CadetTConnection *connection_head;
- struct CadetTConnection *connection_tail;
-
- /**
- * Next connection number.
- */
- uint32_t next_cid;
-
- /**
- * Channels inside this tunnel.
- */
- struct CadetTChannel *channel_head;
- struct CadetTChannel *channel_tail;
-
- /**
- * Channel ID for the next created channel.
- */
- CADET_ChannelNumber next_chid;
-
- /**
- * Destroy flag: if true, destroy on last message.
- */
- GNUNET_SCHEDULER_TaskIdentifier destroy_task;
-
- /**
- * Queued messages, to transmit once tunnel gets connected.
- */
- struct CadetTunnelDelayed *tq_head;
- struct CadetTunnelDelayed *tq_tail;
-};
-
-
-/**
- * Struct used to save messages in a non-ready tunnel to send once connected.
- */
-struct CadetTunnelDelayed
-{
- /**
- * DLL
- */
- struct CadetTunnelDelayed *next;
- struct CadetTunnelDelayed *prev;
-
- /**
- * Tunnel.
- */
- struct CadetTunnel3 *t;
-
- /**
- * Tunnel queue given to the channel to cancel request. Update on
send_queued.
- */
- struct CadetTunnel3Queue *tq;
-
- /**
- * Message to send.
- */
- /* struct GNUNET_MessageHeader *msg; */
-};
-
-
-/**
- * Handle for messages queued but not yet sent.
- */
-struct CadetTunnel3Queue
-{
- /**
- * Connection queue handle, to cancel if necessary.
- */
- struct CadetConnectionQueue *cq;
-
- /**
- * Handle in case message hasn't been given to a connection yet.
- */
- struct CadetTunnelDelayed *tqd;
-
- /**
- * Continuation to call once sent.
- */
- GMT_sent cont;
-
- /**
- * Closure for @c cont.
- */
- void *cont_cls;
-};
-
-
-/******************************************************************************/
-/******************************* GLOBALS
***********************************/
-/******************************************************************************/
-
-/**
- * Global handle to the statistics service.
- */
-extern struct GNUNET_STATISTICS_Handle *stats;
-
-/**
- * Local peer own ID (memory efficient handle).
- */
-extern GNUNET_PEER_Id myid;
-
-/**
- * Local peer own ID (full value).
- */
-extern struct GNUNET_PeerIdentity my_full_id;
-
-
-/**
- * Don't try to recover tunnels if shutting down.
- */
-extern int shutting_down;
-
-
-/**
- * Set of all tunnels, in order to trigger a new exchange on rekey.
- * Indexed by peer's ID.
- */
-static struct GNUNET_CONTAINER_MultiPeerMap *tunnels;
-
-/**
- * Default TTL for payload packets.
- */
-static unsigned long long default_ttl;
-
-/**
- * Own private key.
- */
-const static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
-
-/**
- * Own ephemeral private key.
- */
-static struct GNUNET_CRYPTO_EcdhePrivateKey *my_ephemeral_key;
-
-/**
- * Cached message used to perform a key exchange.
- */
-static struct GNUNET_CADET_KX_Ephemeral kx_msg;
-
-/**
- * Task to generate a new ephemeral key.
- */
-static GNUNET_SCHEDULER_TaskIdentifier rekey_task;
-
-/**
- * Rekey period.
- */
-static struct GNUNET_TIME_Relative rekey_period;
-
-/******************************************************************************/
-/******************************** STATIC
***********************************/
-/******************************************************************************/
-
-/**
- * Get string description for tunnel connectivity state.
- *
- * @param cs Tunnel state.
- *
- * @return String representation.
- */
-static const char *
-cstate2s (enum CadetTunnel3CState cs)
-{
- static char buf[128];
-
- switch (cs)
- {
- case CADET_TUNNEL3_NEW:
- return "CADET_TUNNEL3_NEW";
- case CADET_TUNNEL3_SEARCHING:
- return "CADET_TUNNEL3_SEARCHING";
- case CADET_TUNNEL3_WAITING:
- return "CADET_TUNNEL3_WAITING";
- case CADET_TUNNEL3_READY:
- return "CADET_TUNNEL3_READY";
-
- default:
- sprintf (buf, "%u (UNKNOWN STATE)", cs);
- return buf;
- }
- return "";
-}
-
-
-/**
- * Get string description for tunnel encryption state.
- *
- * @param es Tunnel state.
- *
- * @return String representation.
- */
-static const char *
-estate2s (enum CadetTunnel3EState es)
-{
- static char buf[128];
-
- switch (es)
- {
- case CADET_TUNNEL3_KEY_UNINITIALIZED:
- return "CADET_TUNNEL3_KEY_UNINITIALIZED";
- case CADET_TUNNEL3_KEY_SENT:
- return "CADET_TUNNEL3_KEY_SENT";
- case CADET_TUNNEL3_KEY_PING:
- return "CADET_TUNNEL3_KEY_PING";
- case CADET_TUNNEL3_KEY_OK:
- return "CADET_TUNNEL3_KEY_OK";
-
- default:
- sprintf (buf, "%u (UNKNOWN STATE)", es);
- return buf;
- }
- return "";
-}
-
-
-/**
- * @brief Check if tunnel is ready to send traffic.
- *
- * Tunnel must be connected and with encryption correctly set up.
- *
- * @param t Tunnel to check.
- *
- * @return #GNUNET_YES if ready, #GNUNET_NO otherwise
- */
-static int
-is_ready (struct CadetTunnel3 *t)
-{
- int ready;
-
- GMT_debug (t);
- ready = (CADET_TUNNEL3_READY == t->cstate && CADET_TUNNEL3_KEY_OK ==
t->estate);
- ready = ready || GMT_is_loopback (t);
- return ready;
-}
-
-
-/**
- * Ephemeral key message purpose size.
- *
- * @return Size of the part of the ephemeral key message that must be signed.
- */
-size_t
-ephemeral_purpose_size (void)
-{
- return sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
- sizeof (struct GNUNET_TIME_AbsoluteNBO) +
- sizeof (struct GNUNET_TIME_AbsoluteNBO) +
- sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) +
- sizeof (struct GNUNET_PeerIdentity);
-}
-
-
-/**
- * Size of the encrypted part of a ping message.
- *
- * @return Size of the encrypted part of a ping message.
- */
-size_t
-ping_encryption_size (void)
-{
- return sizeof (struct GNUNET_PeerIdentity) + sizeof (uint32_t);
-}
-
-
-/**
- * Get the channel's buffer. ONLY FOR NON-LOOPBACK CHANNELS!!
- *
- * @param tch Tunnel's channel handle.
- *
- * @return Amount of messages the channel can still buffer towards the client.
- */
-static unsigned int
-get_channel_buffer (const struct CadetTChannel *tch)
-{
- int fwd;
-
- /* If channel is outgoing, is origin in the FWD direction and fwd is YES */
- fwd = GMCH_is_origin (tch->ch, GNUNET_YES);
-
- return GMCH_get_buffer (tch->ch, fwd);
-}
-
-
-/**
- * Get the channel's allowance status.
- *
- * @param tch Tunnel's channel handle.
- *
- * @return #GNUNET_YES if we allowed the client to send data to us.
- */
-static int
-get_channel_allowed (const struct CadetTChannel *tch)
-{
- int fwd;
-
- /* If channel is outgoing, is origin in the FWD direction and fwd is YES */
- fwd = GMCH_is_origin (tch->ch, GNUNET_YES);
-
- return GMCH_get_allowed (tch->ch, fwd);
-}
-
-
-/**
- * Get the connection's buffer.
- *
- * @param tc Tunnel's connection handle.
- *
- * @return Amount of messages the connection can still buffer.
- */
-static unsigned int
-get_connection_buffer (const struct CadetTConnection *tc)
-{
- int fwd;
-
- /* If connection is outgoing, is origin in the FWD direction and fwd is YES
*/
- fwd = GMC_is_origin (tc->c, GNUNET_YES);
-
- return GMC_get_buffer (tc->c, fwd);
-}
-
-
-/**
- * Get the connection's allowance.
- *
- * @param tc Tunnel's connection handle.
- *
- * @return Amount of messages we have allowed the next peer to send us.
- */
-static unsigned int
-get_connection_allowed (const struct CadetTConnection *tc)
-{
- int fwd;
-
- /* If connection is outgoing, is origin in the FWD direction and fwd is YES
*/
- fwd = GMC_is_origin (tc->c, GNUNET_YES);
-
- return GMC_get_allowed (tc->c, fwd);
-}
-
-
-/**
- * Check that a ephemeral key message s well formed and correctly signed.
- *
- * @param t Tunnel on which the message came.
- * @param msg The ephemeral key message.
- *
- * @return GNUNET_OK if message is fine, GNUNET_SYSERR otherwise.
- */
-int
-check_ephemeral (struct CadetTunnel3 *t,
- const struct GNUNET_CADET_KX_Ephemeral *msg)
-{
- /* Check message size */
- if (ntohs (msg->header.size) != sizeof (struct GNUNET_CADET_KX_Ephemeral))
- return GNUNET_SYSERR;
-
- /* Check signature size */
- if (ntohl (msg->purpose.size) != ephemeral_purpose_size ())
- return GNUNET_SYSERR;
-
- /* Check origin */
- if (0 != memcmp (&msg->origin_identity,
- GMP_get_id (t->peer),
- sizeof (struct GNUNET_PeerIdentity)))
- return GNUNET_SYSERR;
-
- /* Check signature */
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_CADET_KX,
- &msg->purpose,
- &msg->signature,
- &msg->origin_identity.public_key))
- return GNUNET_SYSERR;
-
- return GNUNET_OK;
-}
-
-
-/**
- * Encrypt data with the tunnel key.
- *
- * @param t Tunnel whose key to use.
- * @param dst Destination for the encrypted data.
- * @param src Source of the plaintext. Can overlap with @c dst.
- * @param size Size of the plaintext.
- * @param iv Initialization Vector to use.
- */
-static int
-t_encrypt (struct CadetTunnel3 *t,
- void *dst, const void *src,
- size_t size, uint32_t iv)
-{
- struct GNUNET_CRYPTO_SymmetricInitializationVector siv;
- size_t out_size;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " t_encrypt start\n");
- GNUNET_CRYPTO_symmetric_derive_iv (&siv, &t->e_key, &iv, sizeof (iv), NULL);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " t_encrypt IV derived\n");
- out_size = GNUNET_CRYPTO_symmetric_encrypt (src, size, &t->e_key, &siv, dst);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " t_encrypt end\n");
-
- return out_size;
-}
-
-
-/**
- * Decrypt data with the tunnel key.
- *
- * @param t Tunnel whose key to use.
- * @param dst Destination for the plaintext.
- * @param src Source of the encrypted data. Can overlap with @c dst.
- * @param size Size of the encrypted data.
- * @param iv Initialization Vector to use.
- */
-static int
-t_decrypt (struct CadetTunnel3 *t,
- void *dst, const void *src,
- size_t size, uint32_t iv)
-{
- struct GNUNET_CRYPTO_SymmetricInitializationVector siv;
- struct GNUNET_CRYPTO_SymmetricSessionKey *key;
- size_t out_size;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " t_decrypt start\n");
- if (t->estate == CADET_TUNNEL3_KEY_OK || t->estate == CADET_TUNNEL3_KEY_PING)
- {
- key = &t->d_key;
- }
- else if (NULL != t->kx_ctx)
- {
- key = &t->kx_ctx->d_key_old;
- }
- else
- {
- GNUNET_STATISTICS_update (stats, "# non decryptable data", 1, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "WARNING got data on %s without a valid key\n",
- GMT_2s (t));
- GMT_debug (t);
- return 0;
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " t_decrypt iv\n");
- GNUNET_CRYPTO_symmetric_derive_iv (&siv, key, &iv, sizeof (iv), NULL);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " t_decrypt iv done\n");
- out_size = GNUNET_CRYPTO_symmetric_decrypt (src, size, key, &siv, dst);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " t_decrypt end\n");
-
- return out_size;
-}
-
-
-/**
- * Create key material by doing ECDH on the local and remote ephemeral keys.
- *
- * @param key_material Where to store the key material.
- * @param ephemeral_key Peer's public ephemeral key.
- */
-void
-derive_key_material (struct GNUNET_HashCode *key_material,
- const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key)
-{
- if (GNUNET_OK !=
- GNUNET_CRYPTO_ecc_ecdh (my_ephemeral_key,
- ephemeral_key,
- key_material))
- {
- GNUNET_break (0);
- }
-}
-
-/**
- * Create a symmetic key from the identities of both ends and the key material
- * from ECDH.
- *
- * @param key Destination for the generated key.
- * @param sender ID of the peer that will encrypt with @c key.
- * @param receiver ID of the peer that will decrypt with @c key.
- * @param key_material Hash created with ECDH with the ephemeral keys.
- */
-void
-derive_symmertic (struct GNUNET_CRYPTO_SymmetricSessionKey *key,
- const struct GNUNET_PeerIdentity *sender,
- const struct GNUNET_PeerIdentity *receiver,
- const struct GNUNET_HashCode *key_material)
-{
- const char salt[] = "CADET kx salt";
-
- GNUNET_CRYPTO_kdf (key, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
- salt, sizeof (salt),
- key_material, sizeof (struct GNUNET_HashCode),
- sender, sizeof (struct GNUNET_PeerIdentity),
- receiver, sizeof (struct GNUNET_PeerIdentity),
- NULL);
-}
-
-/**
- * Pick a connection on which send the next data message.
- *
- * @param t Tunnel on which to send the message.
- *
- * @return The connection on which to send the next message.
- */
-static struct CadetConnection *
-tunnel_get_connection (struct CadetTunnel3 *t)
-{
- struct CadetTConnection *iter;
- struct CadetConnection *best;
- unsigned int qn;
- unsigned int lowest_q;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel_get_connection %s\n", GMT_2s (t));
- best = NULL;
- lowest_q = UINT_MAX;
- for (iter = t->connection_head; NULL != iter; iter = iter->next)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " connection %s: %u\n",
- GMC_2s (iter->c), GMC_get_state (iter->c));
- if (CADET_CONNECTION_READY == GMC_get_state (iter->c))
- {
- qn = GMC_get_qn (iter->c, GMC_is_origin (iter->c, GNUNET_YES));
- LOG (GNUNET_ERROR_TYPE_DEBUG, " q_n %u, \n", qn);
- if (qn < lowest_q)
- {
- best = iter->c;
- lowest_q = qn;
- }
- }
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " selected: connection %s\n", GMC_2s (best));
- return best;
-}
-
-
-/**
- * Callback called when a queued message is sent.
- *
- * Calculates the average time and connection packet tracking.
- *
- * @param cls Closure (TunnelQueue handle).
- * @param c Connection this message was on.
- * @param q Connection queue handle (unused).
- * @param type Type of message sent.
- * @param fwd Was this a FWD going message?
- * @param size Size of the message.
- */
-static void
-tun_message_sent (void *cls,
- struct CadetConnection *c,
- struct CadetConnectionQueue *q,
- uint16_t type, int fwd, size_t size)
-{
- struct CadetTunnel3Queue *qt = cls;
- struct CadetTunnel3 *t;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "tun_message_sent\n");
-
- GNUNET_assert (NULL != qt->cont);
- t = NULL == c ? NULL : GMC_get_tunnel (c);
- qt->cont (qt->cont_cls, t, qt, type, size);
- GNUNET_free (qt);
-}
-
-
-/**
- * Delete a queued message: either was sent or the channel was destroyed
- * before the tunnel's key exchange had a chance to finish.
- *
- * @param tqd Delayed queue handle.
- */
-static void
-unqueue_data (struct CadetTunnelDelayed *tqd)
-{
- GNUNET_CONTAINER_DLL_remove (tqd->t->tq_head, tqd->t->tq_tail, tqd);
- GNUNET_free (tqd);
-}
-
-
-/**
- * Cache a message to be sent once tunnel is online.
- *
- * @param t Tunnel to hold the message.
- * @param msg Message itself (copy will be made).
- */
-static struct CadetTunnelDelayed *
-queue_data (struct CadetTunnel3 *t, const struct GNUNET_MessageHeader *msg)
-{
- struct CadetTunnelDelayed *tqd;
- uint16_t size = ntohs (msg->size);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "queue data on Tunnel %s\n", GMT_2s (t));
-
- if (GNUNET_YES == is_ready (t))
- {
- GNUNET_break (0);
- return NULL;
- }
-
- tqd = GNUNET_malloc (sizeof (struct CadetTunnelDelayed) + size);
-
- tqd->t = t;
- memcpy (&tqd[1], msg, size);
- GNUNET_CONTAINER_DLL_insert_tail (t->tq_head, t->tq_tail, tqd);
- return tqd;
-}
-
-
-/**
- * Calculate HMAC.
- *
- * @param t Tunnel to get keys from.
- * @param plaintext Content to HMAC.
- * @param size Size of @c plaintext.
- * @param iv Initialization vector for the message.
- * @param outgoing Is this an outgoing message that we encrypted?
- * @param hmac Destination to store the HMAC.
- */
-static void
-t_hmac (struct CadetTunnel3 *t, const void *plaintext, size_t size, uint32_t
iv,
- int outgoing, struct GNUNET_CADET_Hash *hmac)
-{
- struct GNUNET_CRYPTO_AuthKey auth_key;
- static const char ctx[] = "cadet authentication key";
- struct GNUNET_CRYPTO_SymmetricSessionKey *key;
- struct GNUNET_HashCode hash;
-
- key = outgoing ? &t->e_key : &t->d_key;
- GNUNET_CRYPTO_hmac_derive_key (&auth_key, key,
- &iv, sizeof (iv),
- key, sizeof (*key),
- ctx, sizeof (ctx),
- NULL);
- GNUNET_CRYPTO_hmac (&auth_key, plaintext, size, &hash);
- memcpy (hmac, &hash, sizeof (*hmac));
-}
-
-
-/**
- * Sends an already built message on a tunnel, encrypting it and
- * choosing the best connection.
- *
- * @param message Message to send. Function modifies it.
- * @param t Tunnel on which this message is transmitted.
- * @param c Connection to use (autoselect if NULL).
- * @param force Force the tunnel to take the message (buffer overfill).
- * @param cont Continuation to call once message is really sent.
- * @param cont_cls Closure for @c cont.
- * @param existing_q In case this a transmission of previously queued data,
- * this should be TunnelQueue given to the client.
- * Otherwise, NULL.
- *
- * @return Handle to cancel message. NULL if @c cont is NULL.
- */
-static struct CadetTunnel3Queue *
-send_prebuilt_message (const struct GNUNET_MessageHeader *message,
- struct CadetTunnel3 *t, struct CadetConnection *c,
- int force, GMT_sent cont, void *cont_cls,
- struct CadetTunnel3Queue *existing_q)
-{
- struct CadetTunnel3Queue *tq;
- struct GNUNET_CADET_Encrypted *msg;
- size_t size = ntohs (message->size);
- char cbuf[sizeof (struct GNUNET_CADET_Encrypted) + size];
- uint32_t mid;
- uint32_t iv;
- uint16_t type;
- int fwd;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT Send on Tunnel %s\n", GMT_2s (t));
-
- if (GNUNET_NO == is_ready (t))
- {
- struct CadetTunnelDelayed *tqd;
- /* A non null existing_q indicates sending of queued data.
- * Should only happen after tunnel becomes ready.
- */
- GNUNET_assert (NULL == existing_q);
- tqd = queue_data (t, message);
- if (NULL == cont)
- return NULL;
- tq = GNUNET_new (struct CadetTunnel3Queue);
- tq->tqd = tqd;
- tqd->tq = tq;
- tq->cont = cont;
- tq->cont_cls = cont_cls;
- return tq;
- }
-
- GNUNET_assert (GNUNET_NO == GMT_is_loopback (t));
-
- iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
- msg = (struct GNUNET_CADET_Encrypted *) cbuf;
- msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED);
- msg->iv = iv;
- GNUNET_assert (t_encrypt (t, &msg[1], message, size, iv) == size);
- t_hmac (t, &msg[1], size, iv, GNUNET_YES, &msg->hmac);
- msg->header.size = htons (sizeof (struct GNUNET_CADET_Encrypted) + size);
-
- if (NULL == c)
- c = tunnel_get_connection (t);
- if (NULL == c)
- {
- if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task
- || CADET_TUNNEL3_SEARCHING != t->cstate)
- {
- GNUNET_break (0);
- GMT_debug (t);
- }
- return NULL;
- }
-
- mid = 0;
- type = ntohs (message->type);
- switch (type)
- {
- case GNUNET_MESSAGE_TYPE_CADET_DATA:
- case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK:
- if (GNUNET_MESSAGE_TYPE_CADET_DATA == type)
- mid = ntohl (((struct GNUNET_CADET_Data *) message)->mid);
- else
- mid = ntohl (((struct GNUNET_CADET_DataACK *) message)->mid);
- /* Fall thru */
- case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK:
- msg->cid = *GMC_get_id (c);
- msg->ttl = htonl (default_ttl);
- break;
- default:
- GNUNET_break (0);
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "type %s\n", GM_m2s (type));
-
- fwd = GMC_is_origin (c, GNUNET_YES);
-
- if (NULL == cont)
- {
- GNUNET_break (NULL ==
- GMC_send_prebuilt_message (&msg->header, type, mid,
- c, fwd, force, NULL, NULL));
- return NULL;
- }
- if (NULL == existing_q)
- {
- tq = GNUNET_new (struct CadetTunnel3Queue); /* FIXME valgrind: leak*/
- }
- else
- {
- tq = existing_q;
- tq->tqd = NULL;
- }
- tq->cq = GMC_send_prebuilt_message (&msg->header, type, mid, c, fwd, force,
- &tun_message_sent, tq);
- tq->cont = cont;
- tq->cont_cls = cont_cls;
-
- return tq;
-}
-
-
-/**
- * Send all cached messages that we can, tunnel is online.
- *
- * @param t Tunnel that holds the messages. Cannot be loopback.
- */
-static void
-send_queued_data (struct CadetTunnel3 *t)
-{
- struct CadetTunnelDelayed *tqd;
- struct CadetTunnelDelayed *next;
- unsigned int room;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "GMT_send_queued_data on tunnel %s\n",
- GMT_2s (t));
-
- if (GMT_is_loopback (t))
- {
- GNUNET_break (0);
- return;
- }
-
- if (GNUNET_NO == is_ready (t))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " not ready yet: %s/%s\n",
- estate2s (t->estate), cstate2s (t->cstate));
- return;
- }
-
- room = GMT_get_connections_buffer (t);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space: %u\n", room);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " tq head: %p\n", t->tq_head);
- for (tqd = t->tq_head; NULL != tqd && room > 0; tqd = next)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " sending queued data\n");
- next = tqd->next;
- room--;
- send_prebuilt_message ((struct GNUNET_MessageHeader *) &tqd[1],
- tqd->t, NULL, GNUNET_YES,
- NULL != tqd->tq ? tqd->tq->cont : NULL,
- NULL != tqd->tq ? tqd->tq->cont_cls : NULL,
- tqd->tq);
- unqueue_data (tqd);
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT_send_queued_data end\n", GMP_2s
(t->peer));
-}
-
-
-/**
- * Sends key exchange message on a tunnel, choosing the best connection.
- * Should not be called on loopback tunnels.
- *
- * @param t Tunnel on which this message is transmitted.
- * @param message Message to send. Function modifies it.
- */
-static void
-send_kx (struct CadetTunnel3 *t,
- const struct GNUNET_MessageHeader *message)
-{
- struct CadetConnection *c;
- struct GNUNET_CADET_KX *msg;
- size_t size = ntohs (message->size);
- char cbuf[sizeof (struct GNUNET_CADET_KX) + size];
- uint16_t type;
- int fwd;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT KX on Tunnel %s\n", GMT_2s (t));
-
- /* Avoid loopback. */
- if (GMT_is_loopback (t))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " loopback!\n");
- GNUNET_break (0);
- return;
- }
-
- if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " being destroyed, why bother\n");
- return;
- }
-
- /* Must have a connection. */
- if (NULL == t->connection_head)
- {
- GNUNET_break (CADET_TUNNEL3_SEARCHING == t->cstate);
- GMT_debug (t);
- return;
- }
-
- msg = (struct GNUNET_CADET_KX *) cbuf;
- msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_KX);
- msg->header.size = htons (sizeof (struct GNUNET_CADET_KX) + size);
- c = tunnel_get_connection (t);
- if (NULL == c)
- {
- GNUNET_break (GNUNET_SCHEDULER_NO_TASK != t->destroy_task
- || CADET_TUNNEL3_READY != t->cstate);
- GMT_debug (t);
- return;
- }
- type = ntohs (message->type);
- switch (type)
- {
- case GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL:
- case GNUNET_MESSAGE_TYPE_CADET_KX_PING:
- case GNUNET_MESSAGE_TYPE_CADET_KX_PONG:
- memcpy (&msg[1], message, size);
- break;
- default:
- LOG (GNUNET_ERROR_TYPE_DEBUG, "unkown type %s\n",
- GM_m2s (type));
- GNUNET_break (0);
- }
-
- fwd = GMC_is_origin (t->connection_head->c, GNUNET_YES);
- /* TODO save handle and cancel in case of a unneeded retransmission */
- GMC_send_prebuilt_message (&msg->header, GNUNET_MESSAGE_TYPE_CADET_KX,
- message->type, c, fwd, GNUNET_YES, NULL, NULL);
-}
-
-
-/**
- * Send the ephemeral key on a tunnel.
- *
- * @param t Tunnel on which to send the key.
- */
-static void
-send_ephemeral (struct CadetTunnel3 *t)
-{
- LOG (GNUNET_ERROR_TYPE_INFO, "=> EPHM for %s\n", GMT_2s (t));
-
- kx_msg.sender_status = htonl (t->estate);
- send_kx (t, &kx_msg.header);
-}
-
-/**
- * Send a ping message on a tunnel.
- *
- * @param t Tunnel on which to send the ping.
- */
-static void
-send_ping (struct CadetTunnel3 *t)
-{
- struct GNUNET_CADET_KX_Ping msg;
-
- LOG (GNUNET_ERROR_TYPE_INFO, "=> PING for %s\n", GMT_2s (t));
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_KX_PING);
- msg.iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
- msg.target = *GMP_get_id (t->peer);
- msg.nonce = t->kx_ctx->challenge;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " sending %u\n", msg.nonce);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " towards %s\n", GNUNET_i2s (&msg.target));
- t_encrypt (t, &msg.target, &msg.target, ping_encryption_size(), msg.iv);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " e sending %u\n", msg.nonce);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " e towards %s\n", GNUNET_i2s (&msg.target));
-
- send_kx (t, &msg.header);
-}
-
-
-/**
- * Send a pong message on a tunnel.
- *
- * @param t Tunnel on which to send the pong.
- * @param challenge Value sent in the ping that we have to send back.
- */
-static void
-send_pong (struct CadetTunnel3 *t, uint32_t challenge)
-{
- struct GNUNET_CADET_KX_Pong msg;
-
- LOG (GNUNET_ERROR_TYPE_INFO, "=> PONG for %s\n", GMT_2s (t));
- msg.header.size = htons (sizeof (msg));
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_KX_PONG);
- msg.iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
- msg.nonce = challenge;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " sending %u\n", msg.nonce);
- t_encrypt (t, &msg.nonce, &msg.nonce, sizeof (msg.nonce), msg.iv);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " e sending %u\n", msg.nonce);
-
- send_kx (t, &msg.header);
-}
-
-
-/**
- * Initiate a rekey with the remote peer.
- *
- * @param cls Closure (tunnel).
- * @param tc TaskContext.
- */
-static void
-rekey_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct CadetTunnel3 *t = cls;
-
- t->rekey_task = GNUNET_SCHEDULER_NO_TASK;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Re-key Tunnel %s\n", GMT_2s (t));
- if (NULL != tc && 0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
- return;
-
- if (NULL == t->kx_ctx)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " new kx ctx\n");
- t->kx_ctx = GNUNET_new (struct CadetTunnelKXCtx);
- t->kx_ctx->challenge =
- GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
- t->kx_ctx->d_key_old = t->d_key;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " new challenge for %s: %u\n",
- GMT_2s (t), t->kx_ctx->challenge);
- }
- send_ephemeral (t);
- switch (t->estate)
- {
- case CADET_TUNNEL3_KEY_UNINITIALIZED:
- t->estate = CADET_TUNNEL3_KEY_SENT;
- break;
- case CADET_TUNNEL3_KEY_SENT:
- break;
- case CADET_TUNNEL3_KEY_PING:
- case CADET_TUNNEL3_KEY_OK:
- send_ping (t);
- t->estate = CADET_TUNNEL3_KEY_PING;
- break;
- default:
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Unexpected state %u\n", t->estate);
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " next call in %s\n",
- GNUNET_STRINGS_relative_time_to_string (REKEY_WAIT, GNUNET_YES));
- t->rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_WAIT, &rekey_tunnel, t);
-}
-
-
-/**
- * Out ephemeral key has changed, create new session key on all tunnels.
- *
- * @param cls Closure (size of the hashmap).
- * @param key Current public key.
- * @param value Value in the hash map (tunnel).
- *
- * @return #GNUNET_YES, so we should continue to iterate,
- */
-static int
-rekey_iterator (void *cls,
- const struct GNUNET_PeerIdentity *key,
- void *value)
-{
- struct CadetTunnel3 *t = value;
- struct GNUNET_TIME_Relative delay;
- long n = (long) cls;
- uint32_t r;
-
- if (GNUNET_SCHEDULER_NO_TASK != t->rekey_task)
- return GNUNET_YES;
-
- if (GNUNET_YES == GMT_is_loopback (t))
- return GNUNET_YES;
-
- r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, (uint32_t) n *
100);
- delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, r);
- t->rekey_task = GNUNET_SCHEDULER_add_delayed (delay, &rekey_tunnel, t);
-
- return GNUNET_YES;
-}
-
-
-/**
- * Create a new ephemeral key and key message, schedule next rekeying.
- *
- * @param cls Closure (unused).
- * @param tc TaskContext.
- */
-static void
-rekey (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct GNUNET_TIME_Absolute time;
- long n;
-
- rekey_task = GNUNET_SCHEDULER_NO_TASK;
-
- if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
- return;
-
- GNUNET_free_non_null (my_ephemeral_key);
- my_ephemeral_key = GNUNET_CRYPTO_ecdhe_key_create ();
-
- time = GNUNET_TIME_absolute_get ();
- kx_msg.creation_time = GNUNET_TIME_absolute_hton (time);
- time = GNUNET_TIME_absolute_add (time, rekey_period);
- time = GNUNET_TIME_absolute_add (time, GNUNET_TIME_UNIT_MINUTES);
- kx_msg.expiration_time = GNUNET_TIME_absolute_hton (time);
- GNUNET_CRYPTO_ecdhe_key_get_public (my_ephemeral_key, &kx_msg.ephemeral_key);
-
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CRYPTO_eddsa_sign (my_private_key,
- &kx_msg.purpose,
- &kx_msg.signature));
-
- n = (long) GNUNET_CONTAINER_multipeermap_size (tunnels);
- GNUNET_CONTAINER_multipeermap_iterate (tunnels, &rekey_iterator, (void *) n);
-
- rekey_task = GNUNET_SCHEDULER_add_delayed (rekey_period, &rekey, NULL);
-}
-
-
-/**
- * Called only on shutdown, destroy every tunnel.
- *
- * @param cls Closure (unused).
- * @param key Current public key.
- * @param value Value in the hash map (tunnel).
- *
- * @return #GNUNET_YES, so we should continue to iterate,
- */
-static int
-destroy_iterator (void *cls,
- const struct GNUNET_PeerIdentity *key,
- void *value)
-{
- struct CadetTunnel3 *t = value;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT_shutdown destroying tunnel at %p\n", t);
- GMT_destroy (t);
- return GNUNET_YES;
-}
-
-
-/**
- * Notify remote peer that we don't know a channel he is talking about,
- * probably CHANNEL_DESTROY was missed.
- *
- * @param t Tunnel on which to notify.
- * @param gid ID of the channel.
- */
-static void
-send_channel_destroy (struct CadetTunnel3 *t, unsigned int gid)
-{
- struct GNUNET_CADET_ChannelManage msg;
-
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
- msg.header.size = htons (sizeof (msg));
- msg.chid = htonl (gid);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "WARNING destroying unknown channel %u on tunnel %s\n",
- gid, GMT_2s (t));
- send_prebuilt_message (&msg.header, t, NULL, GNUNET_YES, NULL, NULL, NULL);
-}
-
-
-/**
- * Demultiplex data per channel and call appropriate channel handler.
- *
- * @param t Tunnel on which the data came.
- * @param msg Data message.
- * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
- * #GNUNET_YES if message is FWD on the respective channel
(loopback)
- * #GNUNET_NO if message is BCK on the respective channel (loopback)
- * #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-static void
-handle_data (struct CadetTunnel3 *t,
- const struct GNUNET_CADET_Data *msg,
- int fwd)
-{
- struct CadetChannel *ch;
- size_t size;
-
- /* Check size */
- size = ntohs (msg->header.size);
- if (size <
- sizeof (struct GNUNET_CADET_Data) +
- sizeof (struct GNUNET_MessageHeader))
- {
- GNUNET_break (0);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " payload of type %s\n",
- GM_m2s (ntohs (msg[1].header.type)));
-
- /* Check channel */
- ch = GMT_get_channel (t, ntohl (msg->chid));
- if (NULL == ch)
- {
- GNUNET_STATISTICS_update (stats, "# data on unknown channel",
- 1, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel 0x%X unknown\n",
- ntohl (msg->chid));
- send_channel_destroy (t, ntohl (msg->chid));
- return;
- }
-
- GMCH_handle_data (ch, msg, fwd);
-}
-
-
-/**
- * Demultiplex data ACKs per channel and update appropriate channel buffer
info.
- *
- * @param t Tunnel on which the DATA ACK came.
- * @param msg DATA ACK message.
- * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
- * #GNUNET_YES if message is FWD on the respective channel
(loopback)
- * #GNUNET_NO if message is BCK on the respective channel (loopback)
- * #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-static void
-handle_data_ack (struct CadetTunnel3 *t,
- const struct GNUNET_CADET_DataACK *msg,
- int fwd)
-{
- struct CadetChannel *ch;
- size_t size;
-
- /* Check size */
- size = ntohs (msg->header.size);
- if (size != sizeof (struct GNUNET_CADET_DataACK))
- {
- GNUNET_break (0);
- return;
- }
-
- /* Check channel */
- ch = GMT_get_channel (t, ntohl (msg->chid));
- if (NULL == ch)
- {
- GNUNET_STATISTICS_update (stats, "# data ack on unknown channel",
- 1, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n",
- ntohl (msg->chid));
- return;
- }
-
- GMCH_handle_data_ack (ch, msg, fwd);
-}
-
-
-/**
- * Handle channel create.
- *
- * @param t Tunnel on which the data came.
- * @param msg Data message.
- */
-static void
-handle_ch_create (struct CadetTunnel3 *t,
- const struct GNUNET_CADET_ChannelCreate *msg)
-{
- struct CadetChannel *ch;
- size_t size;
-
- /* Check size */
- size = ntohs (msg->header.size);
- if (size != sizeof (struct GNUNET_CADET_ChannelCreate))
- {
- GNUNET_break (0);
- return;
- }
-
- /* Check channel */
- ch = GMT_get_channel (t, ntohl (msg->chid));
- if (NULL != ch && ! GMT_is_loopback (t))
- {
- /* Probably a retransmission, safe to ignore */
- LOG (GNUNET_ERROR_TYPE_DEBUG, " already exists...\n");
- }
- ch = GMCH_handle_create (t, msg);
- if (NULL != ch)
- GMT_add_channel (t, ch);
-}
-
-
-
-/**
- * Handle channel NACK: check correctness and call channel handler for NACKs.
- *
- * @param t Tunnel on which the NACK came.
- * @param msg NACK message.
- */
-static void
-handle_ch_nack (struct CadetTunnel3 *t,
- const struct GNUNET_CADET_ChannelManage *msg)
-{
- struct CadetChannel *ch;
- size_t size;
-
- /* Check size */
- size = ntohs (msg->header.size);
- if (size != sizeof (struct GNUNET_CADET_ChannelManage))
- {
- GNUNET_break (0);
- return;
- }
-
- /* Check channel */
- ch = GMT_get_channel (t, ntohl (msg->chid));
- if (NULL == ch)
- {
- GNUNET_STATISTICS_update (stats, "# channel NACK on unknown channel",
- 1, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n",
- ntohl (msg->chid));
- return;
- }
-
- GMCH_handle_nack (ch);
-}
-
-
-/**
- * Handle a CHANNEL ACK (SYNACK/ACK).
- *
- * @param t Tunnel on which the CHANNEL ACK came.
- * @param msg CHANNEL ACK message.
- * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
- * #GNUNET_YES if message is FWD on the respective channel
(loopback)
- * #GNUNET_NO if message is BCK on the respective channel (loopback)
- * #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-static void
-handle_ch_ack (struct CadetTunnel3 *t,
- const struct GNUNET_CADET_ChannelManage *msg,
- int fwd)
-{
- struct CadetChannel *ch;
- size_t size;
-
- /* Check size */
- size = ntohs (msg->header.size);
- if (size != sizeof (struct GNUNET_CADET_ChannelManage))
- {
- GNUNET_break (0);
- return;
- }
-
- /* Check channel */
- ch = GMT_get_channel (t, ntohl (msg->chid));
- if (NULL == ch)
- {
- GNUNET_STATISTICS_update (stats, "# channel ack on unknown channel",
- 1, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n",
- ntohl (msg->chid));
- return;
- }
-
- GMCH_handle_ack (ch, msg, fwd);
-}
-
-
-
-/**
- * Handle a channel destruction message.
- *
- * @param t Tunnel on which the message came.
- * @param msg Channel destroy message.
- * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
- * #GNUNET_YES if message is FWD on the respective channel
(loopback)
- * #GNUNET_NO if message is BCK on the respective channel (loopback)
- * #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-static void
-handle_ch_destroy (struct CadetTunnel3 *t,
- const struct GNUNET_CADET_ChannelManage *msg,
- int fwd)
-{
- struct CadetChannel *ch;
- size_t size;
-
- /* Check size */
- size = ntohs (msg->header.size);
- if (size != sizeof (struct GNUNET_CADET_ChannelManage))
- {
- GNUNET_break (0);
- return;
- }
-
- /* Check channel */
- ch = GMT_get_channel (t, ntohl (msg->chid));
- if (NULL == ch)
- {
- /* Probably a retransmission, safe to ignore */
- return;
- }
-
- GMCH_handle_destroy (ch, msg, fwd);
-}
-
-
-/**
- * The peer's ephemeral key has changed: update the symmetrical keys.
- *
- * @param t Tunnel this message came on.
- * @param msg Key eXchange message.
- */
-static void
-handle_ephemeral (struct CadetTunnel3 *t,
- const struct GNUNET_CADET_KX_Ephemeral *msg)
-{
- struct GNUNET_HashCode km;
- LOG (GNUNET_ERROR_TYPE_INFO, "<=== EPHM for %s\n", GMT_2s (t));
-
- if (GNUNET_OK != check_ephemeral (t, msg))
- {
- GNUNET_break_op (0);
- return;
- }
- derive_key_material (&km, &msg->ephemeral_key);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " km is %s\n", GNUNET_h2s (&km));
- derive_symmertic (&t->e_key, &my_full_id, GMP_get_id (t->peer), &km);
- derive_symmertic (&t->d_key, GMP_get_id (t->peer), &my_full_id, &km);
- if (CADET_TUNNEL3_KEY_SENT == t->estate)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " our key was sent, send ping\n");
- send_ping (t);
- t->estate = CADET_TUNNEL3_KEY_PING;
- }
-}
-
-
-/**
- * Peer wants to check our symmetrical keys by sending an encrypted challenge.
- * Answer with by retransmitting the challenge with the "opposite" key.
- *
- * @param t Tunnel this message came on.
- * @param msg Key eXchange Ping message.
- */
-static void
-handle_ping (struct CadetTunnel3 *t,
- const struct GNUNET_CADET_KX_Ping *msg)
-{
- struct GNUNET_CADET_KX_Ping res;
-
- if (ntohs (msg->header.size) != sizeof (res))
- {
- GNUNET_break_op (0);
- return;
- }
-
- LOG (GNUNET_ERROR_TYPE_INFO, "<=== PING for %s\n", GMT_2s (t));
- t_decrypt (t, &res.target, &msg->target, ping_encryption_size (), msg->iv);
- if (0 != memcmp (&my_full_id, &res.target, sizeof (my_full_id)))
- {
- // FIXME: move to debug
- GNUNET_STATISTICS_update (stats, "# malformed PINGs", 1, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_WARNING, " malformed PING on %s\n", GMT_2s (t));
- LOG (GNUNET_ERROR_TYPE_WARNING, " e got %u\n", msg->nonce);
- LOG (GNUNET_ERROR_TYPE_WARNING, " e towards %s\n", GNUNET_i2s
(&msg->target));
- LOG (GNUNET_ERROR_TYPE_WARNING, " got %u\n", res.nonce);
- LOG (GNUNET_ERROR_TYPE_WARNING, " towards %s\n", GNUNET_i2s
(&res.target));
- return;
- }
-
- send_pong (t, res.nonce);
-}
-
-
-/**
- * Peer has answer to our challenge.
- * If answer is successful, consider the key exchange finished and clean
- * up all related state.
- *
- * @param t Tunnel this message came on.
- * @param msg Key eXchange Pong message.
- */
-static void
-handle_pong (struct CadetTunnel3 *t,
- const struct GNUNET_CADET_KX_Pong *msg)
-{
- uint32_t challenge;
-
- LOG (GNUNET_ERROR_TYPE_INFO, "<=== PONG for %s\n", GMT_2s (t));
- if (GNUNET_SCHEDULER_NO_TASK == t->rekey_task)
- {
- GNUNET_STATISTICS_update (stats, "# duplicate PONG messages", 1,
GNUNET_NO);
- return;
- }
- t_decrypt (t, &challenge, &msg->nonce, sizeof (uint32_t), msg->iv);
-
- if (challenge != t->kx_ctx->challenge)
- {
- LOG (GNUNET_ERROR_TYPE_WARNING, "Wrong PONG challenge\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, "PONG: %u (e: %u). Expected: %u.\n",
- challenge, msg->nonce, t->kx_ctx->challenge);
- GNUNET_break_op (0);
- return;
- }
- GNUNET_SCHEDULER_cancel (t->rekey_task);
- t->rekey_task = GNUNET_SCHEDULER_NO_TASK;
- GNUNET_free (t->kx_ctx);
- t->kx_ctx = NULL;
- GMT_change_estate (t, CADET_TUNNEL3_KEY_OK);
-}
-
-
-/**
- * Demultiplex by message type and call appropriate handler for a message
- * towards a channel of a local tunnel.
- *
- * @param t Tunnel this message came on.
- * @param msgh Message header.
- * @param fwd Is this message fwd? This only is meaningful in loopback
channels.
- * #GNUNET_YES if message is FWD on the respective channel
(loopback)
- * #GNUNET_NO if message is BCK on the respective channel (loopback)
- * #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-static void
-handle_decrypted (struct CadetTunnel3 *t,
- const struct GNUNET_MessageHeader *msgh,
- int fwd)
-{
- uint16_t type;
-
- type = ntohs (msgh->type);
- LOG (GNUNET_ERROR_TYPE_INFO, "<=== %s on %s\n", GM_m2s (type), GMT_2s (t));
-
- switch (type)
- {
- case GNUNET_MESSAGE_TYPE_CADET_KEEPALIVE:
- /* Do nothing, connection aleady got updated. */
- GNUNET_STATISTICS_update (stats, "# keepalives received", 1, GNUNET_NO);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_DATA:
- /* Don't send hop ACK, wait for client to ACK */
- handle_data (t, (struct GNUNET_CADET_Data *) msgh, fwd);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_DATA_ACK:
- handle_data_ack (t, (struct GNUNET_CADET_DataACK *) msgh, fwd);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE:
- handle_ch_create (t,
- (struct GNUNET_CADET_ChannelCreate *) msgh);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_NACK:
- handle_ch_nack (t,
- (struct GNUNET_CADET_ChannelManage *) msgh);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK:
- handle_ch_ack (t,
- (struct GNUNET_CADET_ChannelManage *) msgh,
- fwd);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
- handle_ch_destroy (t,
- (struct GNUNET_CADET_ChannelManage *) msgh,
- fwd);
- break;
-
- default:
- GNUNET_break_op (0);
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "end-to-end message not known (%u)\n",
- ntohs (msgh->type));
- GMT_debug (t);
- }
-}
-
-/******************************************************************************/
-/******************************** API
***********************************/
-/******************************************************************************/
-
-/**
- * Decrypt and demultiplex by message type. Call appropriate handler
- * for every message.
- *
- * @param t Tunnel this message came on.
- * @param msg Encrypted message.
- */
-void
-GMT_handle_encrypted (struct CadetTunnel3 *t,
- const struct GNUNET_CADET_Encrypted *msg)
-{
- size_t size = ntohs (msg->header.size);
- size_t payload_size = size - sizeof (struct GNUNET_CADET_Encrypted);
- size_t decrypted_size;
- char cbuf [payload_size];
- struct GNUNET_MessageHeader *msgh;
- unsigned int off;
- struct GNUNET_CADET_Hash hmac;
-
- decrypted_size = t_decrypt (t, cbuf, &msg[1], payload_size, msg->iv);
- t_hmac (t, &msg[1], payload_size, msg->iv, GNUNET_NO, &hmac);
- if (0 != memcmp (&hmac, &msg->hmac, sizeof (hmac)))
- {
- /* checksum failed */
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed checksum validation for a message on tunnel `%s'\n",
- GMT_2s (t));
- GNUNET_STATISTICS_update (stats, "# wrong HMAC", 1, GNUNET_NO);
- return;
- }
- off = 0;
- while (off < decrypted_size)
- {
- msgh = (struct GNUNET_MessageHeader *) &cbuf[off];
- handle_decrypted (t, msgh, GNUNET_SYSERR);
- off += ntohs (msgh->size);
- }
-}
-
-
-/**
- * Demultiplex an encapsulated KX message by message type.
- *
- * @param t Tunnel on which the message came.
- * @param message Payload of KX message.
- */
-void
-GMT_handle_kx (struct CadetTunnel3 *t,
- const struct GNUNET_MessageHeader *message)
-{
- uint16_t type;
-
- type = ntohs (message->type);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "kx message received\n", type);
- switch (type)
- {
- case GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL:
- handle_ephemeral (t, (struct GNUNET_CADET_KX_Ephemeral *) message);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_KX_PING:
- handle_ping (t, (struct GNUNET_CADET_KX_Ping *) message);
- break;
-
- case GNUNET_MESSAGE_TYPE_CADET_KX_PONG:
- handle_pong (t, (struct GNUNET_CADET_KX_Pong *) message);
- break;
-
- default:
- GNUNET_break_op (0);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "kx message not known (%u)\n", type);
- }
-}
-
-
-/**
- * Initialize the tunnel subsystem.
- *
- * @param c Configuration handle.
- * @param key ECC private key, to derive all other keys and do crypto.
- */
-void
-GMT_init (const struct GNUNET_CONFIGURATION_Handle *c,
- const struct GNUNET_CRYPTO_EddsaPrivateKey *key)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (c, "CADET", "DEFAULT_TTL",
- &default_ttl))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
- "CADET", "DEFAULT_TTL", "USING DEFAULT");
- default_ttl = 64;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (c, "CADET", "REKEY_PERIOD",
- &rekey_period))
- {
- rekey_period = GNUNET_TIME_UNIT_DAYS;
- }
-
- my_private_key = key;
- kx_msg.header.size = htons (sizeof (kx_msg));
- kx_msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_KX_EPHEMERAL);
- kx_msg.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CADET_KX);
- kx_msg.purpose.size = htonl (ephemeral_purpose_size ());
- kx_msg.origin_identity = my_full_id;
- rekey_task = GNUNET_SCHEDULER_add_now (&rekey, NULL);
-
- tunnels = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES);
-}
-
-
-/**
- * Shut down the tunnel subsystem.
- */
-void
-GMT_shutdown (void)
-{
- if (GNUNET_SCHEDULER_NO_TASK != rekey_task)
- {
- GNUNET_SCHEDULER_cancel (rekey_task);
- rekey_task = GNUNET_SCHEDULER_NO_TASK;
- }
- GNUNET_CONTAINER_multipeermap_iterate (tunnels, &destroy_iterator, NULL);
- GNUNET_CONTAINER_multipeermap_destroy (tunnels);
-}
-
-
-/**
- * Create a tunnel.
- *
- * @param destination Peer this tunnel is towards.
- */
-struct CadetTunnel3 *
-GMT_new (struct CadetPeer *destination)
-{
- struct CadetTunnel3 *t;
-
- t = GNUNET_new (struct CadetTunnel3);
- t->next_chid = 0;
- t->peer = destination;
-
- if (GNUNET_OK !=
- GNUNET_CONTAINER_multipeermap_put (tunnels, GMP_get_id (destination), t,
-
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
- {
- GNUNET_break (0);
- GNUNET_free (t);
- return NULL;
- }
- return t;
-}
-
-
-/**
- * Change the tunnel's connection state.
- *
- * @param t Tunnel whose connection state to change.
- * @param cstate New connection state.
- */
-void
-GMT_change_cstate (struct CadetTunnel3* t, enum CadetTunnel3CState cstate)
-{
- if (NULL == t)
- return;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s cstate %s => %s\n",
- GMP_2s (t->peer), cstate2s (t->cstate), cstate2s (cstate));
- if (myid != GMP_get_short_id (t->peer) &&
- CADET_TUNNEL3_READY != t->cstate &&
- CADET_TUNNEL3_READY == cstate)
- {
- t->cstate = cstate;
- if (CADET_TUNNEL3_KEY_OK == t->estate)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered send queued data\n");
- send_queued_data (t);
- }
- else if (CADET_TUNNEL3_KEY_UNINITIALIZED == t->estate)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered rekey\n");
- rekey_tunnel (t, NULL);
- }
- }
- t->cstate = cstate;
-
- if (CADET_TUNNEL3_READY == cstate
- && CONNECTIONS_PER_TUNNEL <= GMT_count_connections (t))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered stop dht\n");
- GMP_stop_search (t->peer);
- }
-}
-
-/**
- * Change the tunnel encryption state.
- *
- * @param t Tunnel whose encryption state to change.
- * @param state New encryption state.
- */
-void
-GMT_change_estate (struct CadetTunnel3* t, enum CadetTunnel3EState state)
-{
- if (NULL == t)
- return;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Tunnel %s estate was %s\n",
- GMP_2s (t->peer), estate2s (t->estate));
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Tunnel %s estate is now %s\n",
- GMP_2s (t->peer), estate2s (state));
- if (myid != GMP_get_short_id (t->peer) &&
- CADET_TUNNEL3_KEY_OK != t->estate && CADET_TUNNEL3_KEY_OK == state)
- {
- t->estate = state;
- send_queued_data (t);
- return;
- }
- t->estate = state;
-}
-
-
-/**
- * @brief Check if tunnel has too many connections, and remove one if
necessary.
- *
- * Currently this means the newest connection, unless it is a direct one.
- * Implemented as a task to avoid freeing a connection that is in the middle
- * of being created/processed.
- *
- * @param cls Closure (Tunnel to check).
- * @param tc Task context.
- */
-static void
-trim_connections (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct CadetTunnel3 *t = cls;
-
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- return;
-
- if (GMT_count_connections (t) > 2 * CONNECTIONS_PER_TUNNEL)
- {
- struct CadetTConnection *iter;
- struct CadetTConnection *c;
-
- for (c = iter = t->connection_head; NULL != iter; iter = iter->next)
- {
- if ((NULL == c || iter->created.abs_value_us > c->created.abs_value_us)
- && GNUNET_NO == GMC_is_direct (iter->c))
- {
- c = iter;
- }
- }
- if (NULL != c)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Too many connections on tunnel %s\n",
- GMT_2s (t));
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying connection %s\n",
- GMC_2s (c->c));
- GMC_destroy (c->c);
- }
- else
- {
- GNUNET_break (0);
- }
- }
-}
-
-
-/**
- * Add a connection to a tunnel.
- *
- * @param t Tunnel.
- * @param c Connection.
- */
-void
-GMT_add_connection (struct CadetTunnel3 *t, struct CadetConnection *c)
-{
- struct CadetTConnection *aux;
-
- GNUNET_assert (NULL != c);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "add connection %s\n", GMC_2s (c));
- LOG (GNUNET_ERROR_TYPE_DEBUG, " to tunnel %s\n", GMT_2s (t));
- for (aux = t->connection_head; aux != NULL; aux = aux->next)
- if (aux->c == c)
- return;
-
- aux = GNUNET_new (struct CadetTConnection);
- aux->c = c;
- aux->created = GNUNET_TIME_absolute_get ();
-
- GNUNET_CONTAINER_DLL_insert (t->connection_head, t->connection_tail, aux);
-
- GNUNET_SCHEDULER_add_now (&trim_connections, t);
-}
-
-
-/**
- * Mark a path as no longer valid for this tunnel: has been tried and failed.
- *
- * @param t Tunnel to update.
- * @param path Invalid path to remove. Is destroyed after removal.
- */
-void
-GMT_remove_path (struct CadetTunnel3 *t, struct CadetPeerPath *path)
-{
- GMP_remove_path (t->peer, path);
-}
-
-
-/**
- * Remove a connection from a tunnel.
- *
- * @param t Tunnel.
- * @param c Connection.
- */
-void
-GMT_remove_connection (struct CadetTunnel3 *t,
- struct CadetConnection *c)
-{
- struct CadetTConnection *aux;
- struct CadetTConnection *next;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing connection %s from tunnel %s\n",
- GMC_2s (c), GMT_2s (t));
- for (aux = t->connection_head; aux != NULL; aux = next)
- {
- next = aux->next;
- if (aux->c == c)
- {
- GNUNET_CONTAINER_DLL_remove (t->connection_head, t->connection_tail,
aux);
- GNUNET_free (aux);
- }
- }
-
- /* Start new connections if needed */
- if (CONNECTIONS_PER_TUNNEL < GMT_count_connections (t)
- && GNUNET_SCHEDULER_NO_TASK == t->destroy_task
- && CADET_TUNNEL3_SHUTDOWN != t->cstate
- && GNUNET_NO == shutting_down)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " no more connections, getting new ones\n");
- t->cstate = CADET_TUNNEL3_SEARCHING;
- GMP_connect (t->peer);
- return;
- }
-
- /* If not marked as ready, no change is needed */
- if (CADET_TUNNEL3_READY != t->cstate)
- return;
-
- /* Check if any connection is ready to maintaing cstate */
- for (aux = t->connection_head; aux != NULL; aux = aux->next)
- if (CADET_CONNECTION_READY == GMC_get_state (aux->c))
- return;
-
- t->cstate = CADET_TUNNEL3_WAITING;
-}
-
-
-/**
- * Add a channel to a tunnel.
- *
- * @param t Tunnel.
- * @param ch Channel.
- */
-void
-GMT_add_channel (struct CadetTunnel3 *t, struct CadetChannel *ch)
-{
- struct CadetTChannel *aux;
-
- GNUNET_assert (NULL != ch);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding channel %p to tunnel %p\n", ch, t);
-
- for (aux = t->channel_head; aux != NULL; aux = aux->next)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " already there %p\n", aux->ch);
- if (aux->ch == ch)
- return;
- }
-
- aux = GNUNET_new (struct CadetTChannel);
- aux->ch = ch;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " adding %p to %p\n", aux, t->channel_head);
- GNUNET_CONTAINER_DLL_insert_tail (t->channel_head, t->channel_tail, aux);
-
- if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task)
- {
- GNUNET_SCHEDULER_cancel (t->destroy_task);
- t->destroy_task = GNUNET_SCHEDULER_NO_TASK;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " undo destroy!\n");
- }
-}
-
-
-/**
- * Remove a channel from a tunnel.
- *
- * @param t Tunnel.
- * @param ch Channel.
- */
-void
-GMT_remove_channel (struct CadetTunnel3 *t, struct CadetChannel *ch)
-{
- struct CadetTChannel *aux;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing channel %p from tunnel %p\n", ch, t);
- for (aux = t->channel_head; aux != NULL; aux = aux->next)
- {
- if (aux->ch == ch)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " found! %s\n", GMCH_2s (ch));
- GNUNET_CONTAINER_DLL_remove (t->channel_head, t->channel_tail, aux);
- GNUNET_free (aux);
- return;
- }
- }
-}
-
-
-/**
- * Search for a channel by global ID.
- *
- * @param t Tunnel containing the channel.
- * @param chid Public channel number.
- *
- * @return channel handler, NULL if doesn't exist
- */
-struct CadetChannel *
-GMT_get_channel (struct CadetTunnel3 *t, CADET_ChannelNumber chid)
-{
- struct CadetTChannel *iter;
-
- if (NULL == t)
- return NULL;
-
- for (iter = t->channel_head; NULL != iter; iter = iter->next)
- {
- if (GMCH_get_id (iter->ch) == chid)
- break;
- }
-
- return NULL == iter ? NULL : iter->ch;
-}
-
-
-/**
- * @brief Destroy a tunnel and free all resources.
- *
- * Should only be called a while after the tunnel has been marked as destroyed,
- * in case there is a new channel added to the same peer shortly after marking
- * the tunnel. This way we avoid a new public key handshake.
- *
- * @param cls Closure (tunnel to destroy).
- * @param tc Task context.
- */
-static void
-delayed_destroy (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct CadetTunnel3 *t = cls;
- struct CadetTConnection *iter;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "delayed destroying tunnel %p\n", t);
- if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "Not destroying tunnel, due to shutdown. "
- "Tunnel at %p should have been freed by GMT_shutdown\n", t);
- return;
- }
- t->destroy_task = GNUNET_SCHEDULER_NO_TASK;
- t->cstate = CADET_TUNNEL3_SHUTDOWN;
-
- for (iter = t->connection_head; NULL != iter; iter = iter->next)
- {
- GMC_send_destroy (iter->c);
- }
- GMT_destroy (t);
-}
-
-
-/**
- * Tunnel is empty: destroy it.
- *
- * Notifies all connections about the destruction.
- *
- * @param t Tunnel to destroy.
- */
-void
-GMT_destroy_empty (struct CadetTunnel3 *t)
-{
- if (GNUNET_YES == shutting_down)
- return; /* Will be destroyed immediately anyway */
-
- if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Tunnel %s is already scheduled for destruction\n",
- GMT_2s (t));
- GNUNET_break (0);
- /* should never happen, tunnel can only become empty once, and the
- * task identifier should be NO_TASK (cleaned when the tunnel was created
- * or became un-empty)
- */
- return;
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s empty: destroying scheduled\n",
- GMT_2s (t));
-
- t->destroy_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
- &delayed_destroy, t);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduled destroy of %p as %llX\n",
- t, t->destroy_task);
-}
-
-
-/**
- * Destroy tunnel if empty (no more channels).
- *
- * @param t Tunnel to destroy if empty.
- */
-void
-GMT_destroy_if_empty (struct CadetTunnel3 *t)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s destroy if empty\n", GMT_2s (t));
- if (1 < GMT_count_channels (t))
- return;
-
- GMT_destroy_empty (t);
-}
-
-
-/**
- * Destroy the tunnel.
- *
- * This function does not generate any warning traffic to clients or peers.
- *
- * Tasks:
- * Cancel messages belonging to this tunnel queued to neighbors.
- * Free any allocated resources linked to the tunnel.
- *
- * @param t The tunnel to destroy.
- */
-void
-GMT_destroy (struct CadetTunnel3 *t)
-{
- struct CadetTConnection *iter_c;
- struct CadetTConnection *next_c;
- struct CadetTChannel *iter_ch;
- struct CadetTChannel *next_ch;
-
- if (NULL == t)
- return;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying tunnel %s\n", GMP_2s (t->peer));
-
- GNUNET_break (GNUNET_YES ==
- GNUNET_CONTAINER_multipeermap_remove (tunnels,
- GMP_get_id (t->peer),
t));
-
- for (iter_c = t->connection_head; NULL != iter_c; iter_c = next_c)
- {
- next_c = iter_c->next;
- GMC_destroy (iter_c->c);
- }
- for (iter_ch = t->channel_head; NULL != iter_ch; iter_ch = next_ch)
- {
- next_ch = iter_ch->next;
- GMCH_destroy (iter_ch->ch);
- /* Should only happen on shutdown, but it's ok. */
- }
-
- if (GNUNET_SCHEDULER_NO_TASK != t->destroy_task)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "cancelling %llX\n", t->destroy_task);
- GNUNET_SCHEDULER_cancel (t->destroy_task);
- t->destroy_task = GNUNET_SCHEDULER_NO_TASK;
- }
-
- GNUNET_STATISTICS_update (stats, "# tunnels", -1, GNUNET_NO);
- GMP_set_tunnel (t->peer, NULL);
-
- if (GNUNET_SCHEDULER_NO_TASK != t->rekey_task)
- {
- GNUNET_SCHEDULER_cancel (t->rekey_task);
- t->rekey_task = GNUNET_SCHEDULER_NO_TASK;
- if (NULL != t->kx_ctx)
- GNUNET_free (t->kx_ctx);
- else
- GNUNET_break (0);
- }
-
- GNUNET_free (t);
-}
-
-
-/**
- * @brief Use the given path for the tunnel.
- * Update the next and prev hops (and RCs).
- * (Re)start the path refresh in case the tunnel is locally owned.
- *
- * @param t Tunnel to update.
- * @param p Path to use.
- *
- * @return Connection created.
- */
-struct CadetConnection *
-GMT_use_path (struct CadetTunnel3 *t, struct CadetPeerPath *p)
-{
- struct CadetConnection *c;
- struct GNUNET_CADET_Hash cid;
- unsigned int own_pos;
-
- if (NULL == t || NULL == p)
- {
- GNUNET_break (0);
- return NULL;
- }
-
- if (CADET_TUNNEL3_SHUTDOWN == t->cstate)
- {
- GNUNET_break (0);
- return NULL;
- }
-
- for (own_pos = 0; own_pos < p->length; own_pos++)
- {
- if (p->peers[own_pos] == myid)
- break;
- }
- if (own_pos >= p->length)
- {
- GNUNET_break_op (0);
- return NULL;
- }
-
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, &cid, sizeof (cid));
- c = GMC_new (&cid, t, p, own_pos);
- if (NULL == c)
- {
- /* Path was flawed */
- return NULL;
- }
- GMT_add_connection (t, c);
- return c;
-}
-
-
-/**
- * Count established (ready) connections of a tunnel.
- *
- * @param t Tunnel on which to count.
- *
- * @return Number of connections.
- */
-unsigned int
-GMT_count_connections (struct CadetTunnel3 *t)
-{
- struct CadetTConnection *iter;
- unsigned int count;
-
- if (NULL == t)
- return 0;
-
- for (count = 0, iter = t->connection_head; NULL != iter; iter = iter->next)
- if (CADET_CONNECTION_DESTROYED != GMC_get_state (iter->c))
- count++;
-
- return count;
-}
-
-/**
- * Count channels of a tunnel.
- *
- * @param t Tunnel on which to count.
- *
- * @return Number of channels.
- */
-unsigned int
-GMT_count_channels (struct CadetTunnel3 *t)
-{
- struct CadetTChannel *iter;
- unsigned int count;
-
- for (count = 0, iter = t->channel_head;
- NULL != iter;
- iter = iter->next, count++) /* skip */;
-
- return count;
-}
-
-
-/**
- * Get the connectivity state of a tunnel.
- *
- * @param t Tunnel.
- *
- * @return Tunnel's connectivity state.
- */
-enum CadetTunnel3CState
-GMT_get_cstate (struct CadetTunnel3 *t)
-{
- if (NULL == t)
- {
- GNUNET_assert (0);
- return (enum CadetTunnel3CState) -1;
- }
- return t->cstate;
-}
-
-
-/**
- * Get the encryption state of a tunnel.
- *
- * @param t Tunnel.
- *
- * @return Tunnel's encryption state.
- */
-enum CadetTunnel3EState
-GMT_get_estate (struct CadetTunnel3 *t)
-{
- if (NULL == t)
- {
- GNUNET_assert (0);
- return (enum CadetTunnel3EState) -1;
- }
- return t->estate;
-}
-
-/**
- * Get the maximum buffer space for a tunnel towards a local client.
- *
- * @param t Tunnel.
- *
- * @return Biggest buffer space offered by any channel in the tunnel.
- */
-unsigned int
-GMT_get_channels_buffer (struct CadetTunnel3 *t)
-{
- struct CadetTChannel *iter;
- unsigned int buffer;
- unsigned int ch_buf;
-
- if (NULL == t->channel_head)
- {
- /* Probably getting buffer for a channel create/handshake. */
- return 64;
- }
-
- buffer = 0;
- for (iter = t->channel_head; NULL != iter; iter = iter->next)
- {
- ch_buf = get_channel_buffer (iter);
- if (ch_buf > buffer)
- buffer = ch_buf;
- }
- return buffer;
-}
-
-
-/**
- * Get the total buffer space for a tunnel for P2P traffic.
- *
- * @param t Tunnel.
- *
- * @return Buffer space offered by all connections in the tunnel.
- */
-unsigned int
-GMT_get_connections_buffer (struct CadetTunnel3 *t)
-{
- struct CadetTConnection *iter;
- unsigned int buffer;
-
- buffer = 0;
- for (iter = t->connection_head; NULL != iter; iter = iter->next)
- {
- if (GMC_get_state (iter->c) != CADET_CONNECTION_READY)
- {
- continue;
- }
- buffer += get_connection_buffer (iter);
- }
-
- return buffer;
-}
-
-
-/**
- * Get the tunnel's destination.
- *
- * @param t Tunnel.
- *
- * @return ID of the destination peer.
- */
-const struct GNUNET_PeerIdentity *
-GMT_get_destination (struct CadetTunnel3 *t)
-{
- return GMP_get_id (t->peer);
-}
-
-
-/**
- * Get the tunnel's next free global channel ID.
- *
- * @param t Tunnel.
- *
- * @return GID of a channel free to use.
- */
-CADET_ChannelNumber
-GMT_get_next_chid (struct CadetTunnel3 *t)
-{
- CADET_ChannelNumber chid;
- CADET_ChannelNumber mask;
- int result;
-
- /* Set bit 30 depending on the ID relationship. Bit 31 is always 0 for GID.
- * If our ID is bigger or loopback tunnel, start at 0, bit 30 = 0
- * If peer's ID is bigger, start at 0x4... bit 30 = 1
- */
- result = GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, GMP_get_id (t->peer));
- if (0 > result)
- mask = 0x40000000;
- else
- mask = 0x0;
- t->next_chid |= mask;
-
- while (NULL != GMT_get_channel (t, t->next_chid))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %u exists...\n", t->next_chid);
- t->next_chid = (t->next_chid + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
- t->next_chid |= mask;
- }
- chid = t->next_chid;
- t->next_chid = (t->next_chid + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
- t->next_chid |= mask;
-
- return chid;
-}
-
-
-/**
- * Send ACK on one or more channels due to buffer in connections.
- *
- * @param t Channel which has some free buffer space.
- */
-void
-GMT_unchoke_channels (struct CadetTunnel3 *t)
-{
- struct CadetTChannel *iter;
- unsigned int buffer;
- unsigned int channels = GMT_count_channels (t);
- unsigned int choked_n;
- struct CadetChannel *choked[channels];
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT_unchoke_channels on %s\n", GMT_2s (t));
- LOG (GNUNET_ERROR_TYPE_DEBUG, " head: %p\n", t->channel_head);
- if (NULL != t->channel_head)
- LOG (GNUNET_ERROR_TYPE_DEBUG, " head ch: %p\n", t->channel_head->ch);
-
- /* Get buffer space */
- buffer = GMT_get_connections_buffer (t);
- if (0 == buffer)
- {
- return;
- }
-
- /* Count and remember choked channels */
- choked_n = 0;
- for (iter = t->channel_head; NULL != iter; iter = iter->next)
- {
- if (GNUNET_NO == get_channel_allowed (iter))
- {
- choked[choked_n++] = iter->ch;
- }
- }
-
- /* Unchoke random channels */
- while (0 < buffer && 0 < choked_n)
- {
- unsigned int r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
- choked_n);
- GMCH_allow_client (choked[r], GMCH_is_origin (choked[r], GNUNET_YES));
- choked_n--;
- buffer--;
- choked[r] = choked[choked_n];
- }
-}
-
-
-/**
- * Send ACK on one or more connections due to buffer space to the client.
- *
- * Iterates all connections of the tunnel and sends ACKs appropriately.
- *
- * @param t Tunnel.
- */
-void
-GMT_send_connection_acks (struct CadetTunnel3 *t)
-{
- struct CadetTConnection *iter;
- uint32_t allowed;
- uint32_t to_allow;
- uint32_t allow_per_connection;
- unsigned int cs;
- unsigned int buffer;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel send connection ACKs on %s\n",
- GMT_2s (t));
-
- if (NULL == t)
- {
- GNUNET_break (0);
- return;
- }
-
- buffer = GMT_get_channels_buffer (t);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer %u\n", buffer);
-
- /* Count connections, how many messages are already allowed */
- cs = GMT_count_connections (t);
- for (allowed = 0, iter = t->connection_head; NULL != iter; iter = iter->next)
- {
- allowed += get_connection_allowed (iter);
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " allowed %u\n", allowed);
-
- /* Make sure there is no overflow */
- if (allowed > buffer)
- {
- return;
- }
-
- /* Authorize connections to send more data */
- to_allow = buffer; /* - allowed; */
-
- for (iter = t->connection_head;
- NULL != iter && to_allow > 0;
- iter = iter->next)
- {
- allow_per_connection = to_allow/cs;
- to_allow -= allow_per_connection;
- cs--;
- if (get_connection_allowed (iter) > 64 / 3)
- {
- continue;
- }
- GMC_allow (iter->c, allow_per_connection,
- GMC_is_origin (iter->c, GNUNET_NO));
- }
-
- GNUNET_break (to_allow == 0);
-}
-
-
-/**
- * Cancel a previously sent message while it's in the queue.
- *
- * ONLY can be called before the continuation given to the send function
- * is called. Once the continuation is called, the message is no longer in the
- * queue.
- *
- * @param q Handle to the queue.
- */
-void
-GMT_cancel (struct CadetTunnel3Queue *q)
-{
- if (NULL != q->cq)
- {
- GMC_cancel (q->cq);
- /* tun_message_sent() will be called and free q */
- }
- else if (NULL != q->tqd)
- {
- unqueue_data (q->tqd);
- q->tqd = NULL;
- if (NULL != q->cont)
- q->cont (q->cont_cls, NULL, q, 0, 0);
- GNUNET_free (q);
- }
- else
- {
- GNUNET_break (0);
- }
-}
-
-
-/**
- * Sends an already built message on a tunnel, encrypting it and
- * choosing the best connection if not provided.
- *
- * @param message Message to send. Function modifies it.
- * @param t Tunnel on which this message is transmitted.
- * @param c Connection to use (autoselect if NULL).
- * @param force Force the tunnel to take the message (buffer overfill).
- * @param cont Continuation to call once message is really sent.
- * @param cont_cls Closure for @c cont.
- *
- * @return Handle to cancel message. NULL if @c cont is NULL.
- */
-struct CadetTunnel3Queue *
-GMT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
- struct CadetTunnel3 *t, struct CadetConnection *c,
- int force, GMT_sent cont, void *cont_cls)
-{
- return send_prebuilt_message (message, t, c, force, cont, cont_cls, NULL);
-}
-
-
-/**
- * Is the tunnel directed towards the local peer?
- *
- * @param t Tunnel.
- *
- * @return #GNUNET_YES if it is loopback.
- */
-int
-GMT_is_loopback (const struct CadetTunnel3 *t)
-{
- return (myid == GMP_get_short_id (t->peer));
-}
-
-
-/**
- * Is the tunnel this path already?
- *
- * @param t Tunnel.
- * @param p Path.
- *
- * @return #GNUNET_YES a connection uses this path.
- */
-int
-GMT_is_path_used (const struct CadetTunnel3 *t, const struct CadetPeerPath *p)
-{
- struct CadetTConnection *iter;
-
- for (iter = t->connection_head; NULL != iter; iter = iter->next)
- if (GMC_get_path (iter->c) == p)
- return GNUNET_YES;
-
- return GNUNET_NO;
-}
-
-
-/**
- * Get a cost of a path for a tunnel considering existing connections.
- *
- * @param t Tunnel.
- * @param path Candidate path.
- *
- * @return Cost of the path (path length + number of overlapping nodes)
- */
-unsigned int
-GMT_get_path_cost (const struct CadetTunnel3 *t,
- const struct CadetPeerPath *path)
-{
- struct CadetTConnection *iter;
- const struct CadetPeerPath *aux;
- unsigned int overlap;
- unsigned int i;
- unsigned int j;
-
- if (NULL == path)
- return 0;
-
- overlap = 0;
- GNUNET_assert (NULL != t);
-
- for (i = 0; i < path->length; i++)
- {
- for (iter = t->connection_head; NULL != iter; iter = iter->next)
- {
- aux = GMC_get_path (iter->c);
- if (NULL == aux)
- continue;
-
- for (j = 0; j < aux->length; j++)
- {
- if (path->peers[i] == aux->peers[j])
- {
- overlap++;
- break;
- }
- }
- }
- }
- return path->length + overlap;
-}
-
-
-/**
- * Get the static string for the peer this tunnel is directed.
- *
- * @param t Tunnel.
- *
- * @return Static string the destination peer's ID.
- */
-const char *
-GMT_2s (const struct CadetTunnel3 *t)
-{
- if (NULL == t)
- return "(NULL)";
-
- return GMP_2s (t->peer);
-}
-
-
-/******************************************************************************/
-/***************************** INFO/DEBUG
*******************************/
-/******************************************************************************/
-
-
-/**
- * Log all possible info about the tunnel state to stderr.
- *
- * @param t Tunnel to debug.
- */
-void
-GMT_debug (const struct CadetTunnel3 *t)
-{
- struct CadetTChannel *iterch;
- struct CadetTConnection *iterc;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT DEBUG TUNNEL TOWARDS %s\n", GMT_2s (t));
- LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT cstate %s, estate %s\n",
- cstate2s (t->cstate), estate2s (t->estate));
- LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT kx_ctx %p, rekey_task %u\n",
- t->kx_ctx, t->rekey_task);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT tq_head %p, tq_tail %p\n",
- t->tq_head, t->tq_tail);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT destroy %u\n", t->destroy_task);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT channels:\n");
- for (iterch = t->channel_head; NULL != iterch; iterch = iterch->next)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT - %s\n", GMCH_2s (iterch->ch));
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT connections:\n");
- for (iterc = t->connection_head; NULL != iterc; iterc = iterc->next)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT - %s [%u] buf: %u/%u (qn %u/%u)\n",
- GMC_2s (iterc->c), GMC_get_state (iterc->c),
- GMC_get_buffer (iterc->c, GNUNET_YES),
- GMC_get_buffer (iterc->c, GNUNET_NO),
- GMC_get_qn (iterc->c, GNUNET_YES),
- GMC_get_qn (iterc->c, GNUNET_NO));
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "TTT DEBUG TUNNEL END\n");
-}
-
-
-/**
- * Iterate all tunnels.
- *
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GMT_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls)
-{
- GNUNET_CONTAINER_multipeermap_iterate (tunnels, iter, cls);
-}
-
-
-/**
- * Count all tunnels.
- *
- * @return Number of tunnels to remote peers kept by this peer.
- */
-unsigned int
-GMT_count_all (void)
-{
- return GNUNET_CONTAINER_multipeermap_size (tunnels);
-}
-
-
-/**
- * Iterate all connections of a tunnel.
- *
- * @param t Tunnel whose connections to iterate.
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GMT_iterate_connections (struct CadetTunnel3 *t, GMT_conn_iter iter, void *cls)
-{
- struct CadetTConnection *ct;
-
- for (ct = t->connection_head; NULL != ct; ct = ct->next)
- iter (cls, ct->c);
-}
-
-
-/**
- * Iterate all channels of a tunnel.
- *
- * @param t Tunnel whose channels to iterate.
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GMT_iterate_channels (struct CadetTunnel3 *t, GMT_chan_iter iter, void *cls)
-{
- struct CadetTChannel *cht;
-
- for (cht = t->channel_head; NULL != cht; cht = cht->next)
- iter (cls, cht->ch);
-}
Deleted: gnunet/src/mesh/gnunet-service-cadet_tunnel.h
===================================================================
--- gnunet/src/mesh/gnunet-service-cadet_tunnel.h 2014-05-07 12:07:02 UTC
(rev 33185)
+++ gnunet/src/mesh/gnunet-service-cadet_tunnel.h 2014-05-07 12:07:16 UTC
(rev 33186)
@@ -1,531 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2013 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_tunnel.h
- * @brief cadet service; dealing with tunnels and crypto
- * @author Bartlomiej Polot
- *
- * All functions in this file should use the prefix GMT (Gnunet Cadet Tunnel)
- */
-
-#ifndef GNUNET_SERVICE_CADET_TUNNEL_H
-#define GNUNET_SERVICE_CADET_TUNNEL_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0 /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-/**
- * All the connectivity states a tunnel can be in.
- */
-enum CadetTunnel3CState
-{
- /**
- * Uninitialized status, should never appear in operation.
- */
- CADET_TUNNEL3_NEW,
-
- /**
- * Path to the peer not known yet.
- */
- CADET_TUNNEL3_SEARCHING,
-
- /**
- * Request sent, not yet answered.
- */
- CADET_TUNNEL3_WAITING,
-
- /**
- * Peer connected and ready to accept data.
- */
- CADET_TUNNEL3_READY,
-
- /**
- * Tunnel being shut down, don't try to keep it alive.
- */
- CADET_TUNNEL3_SHUTDOWN
-};
-
-
-/**
- * All the encryption states a tunnel can be in.
- */
-enum CadetTunnel3EState
-{
- /**
- * Uninitialized status, should never appear in operation.
- */
- CADET_TUNNEL3_KEY_UNINITIALIZED,
-
- /**
- * Ephemeral key sent, waiting for peer's key.
- */
- CADET_TUNNEL3_KEY_SENT,
-
- /**
- * New ephemeral key and ping sent, waiting for pong.
- * This means that we DO have the peer's ephemeral key, otherwise the
- * state would be KEY_SENT.
- */
- CADET_TUNNEL3_KEY_PING,
-
- /**
- * Handshake completed: session key available.
- */
- CADET_TUNNEL3_KEY_OK,
-};
-
-/**
- * Struct containing all information regarding a given peer
- */
-struct CadetTunnel3;
-
-
-#include "gnunet-service-cadet_channel.h"
-#include "gnunet-service-cadet_connection.h"
-#include "gnunet-service-cadet_peer.h"
-
-/**
- * Handle for messages queued but not yet sent.
- */
-struct CadetTunnel3Queue;
-
-/**
- * Callback called when a queued message is sent.
- *
- * @param cls Closure.
- * @param t Tunnel this message was on.
- * @param type Type of message sent.
- * @param size Size of the message.
- */
-typedef void (*GMT_sent) (void *cls,
- struct CadetTunnel3 *t,
- struct CadetTunnel3Queue *q,
- uint16_t type, size_t size);
-
-typedef void (*GMT_conn_iter) (void *cls, struct CadetConnection *c);
-typedef void (*GMT_chan_iter) (void *cls, struct CadetChannel *ch);
-
-
-/******************************************************************************/
-/******************************** API
***********************************/
-/******************************************************************************/
-
-/**
- * Initialize tunnel subsystem.
- *
- * @param c Configuration handle.
- * @param key ECC private key, to derive all other keys and do crypto.
- */
-void
-GMT_init (const struct GNUNET_CONFIGURATION_Handle *c,
- const struct GNUNET_CRYPTO_EddsaPrivateKey *key);
-
-/**
- * Shut down the tunnel subsystem.
- */
-void
-GMT_shutdown (void);
-
-/**
- * Create a tunnel.
- *
- * @param destination Peer this tunnel is towards.
- */
-struct CadetTunnel3 *
-GMT_new (struct CadetPeer *destination);
-
-/**
- * Tunnel is empty: destroy it.
- *
- * Notifies all connections about the destruction.
- *
- * @param t Tunnel to destroy.
- */
-void
-GMT_destroy_empty (struct CadetTunnel3 *t);
-
-/**
- * Destroy tunnel if empty (no more channels).
- *
- * @param t Tunnel to destroy if empty.
- */
-void
-GMT_destroy_if_empty (struct CadetTunnel3 *t);
-
-/**
- * Destroy the tunnel.
- *
- * This function does not generate any warning traffic to clients or peers.
- *
- * Tasks:
- * Cancel messages belonging to this tunnel queued to neighbors.
- * Free any allocated resources linked to the tunnel.
- *
- * @param t The tunnel to destroy.
- */
-void
-GMT_destroy (struct CadetTunnel3 *t);
-
-
-/**
- * Change the tunnel's connection state.
- *
- * @param t Tunnel whose connection state to change.
- * @param cstate New connection state.
- */
-void
-GMT_change_cstate (struct CadetTunnel3* t, enum CadetTunnel3CState cstate);
-
-
-/**
- * Change the tunnel encryption state.
- *
- * @param t Tunnel whose encryption state to change.
- * @param state New encryption state.
- */
-void
-GMT_change_estate (struct CadetTunnel3* t, enum CadetTunnel3EState state);
-
-/**
- * Add a connection to a tunnel.
- *
- * @param t Tunnel.
- * @param c Connection.
- */
-void
-GMT_add_connection (struct CadetTunnel3 *t, struct CadetConnection *c);
-
-/**
- * Mark a path as no longer valid for this tunnel: has been tried and failed.
- *
- * @param t Tunnel to update.
- * @param path Invalid path to remove. Is destroyed after removal.
- */
-void
-GMT_remove_path (struct CadetTunnel3 *t, struct CadetPeerPath *path);
-
-/**
- * Remove a connection from a tunnel.
- *
- * @param t Tunnel.
- * @param c Connection.
- */
-void
-GMT_remove_connection (struct CadetTunnel3 *t, struct CadetConnection *c);
-
-/**
- * Add a channel to a tunnel.
- *
- * @param t Tunnel.
- * @param ch Channel.
- */
-void
-GMT_add_channel (struct CadetTunnel3 *t, struct CadetChannel *ch);
-
-/**
- * Remove a channel from a tunnel.
- *
- * @param t Tunnel.
- * @param ch Channel.
- */
-void
-GMT_remove_channel (struct CadetTunnel3 *t, struct CadetChannel *ch);
-
-/**
- * Search for a channel by global ID.
- *
- * @param t Tunnel containing the channel.
- * @param chid Public channel number.
- *
- * @return channel handler, NULL if doesn't exist
- */
-struct CadetChannel *
-GMT_get_channel (struct CadetTunnel3 *t, CADET_ChannelNumber chid);
-
-/**
- * Decrypt and demultiplex by message type. Call appropriate handler
- * for a message
- * towards a channel of a local tunnel.
- *
- * @param t Tunnel this message came on.
- * @param msg Message header.
- */
-void
-GMT_handle_encrypted (struct CadetTunnel3 *t,
- const struct GNUNET_CADET_Encrypted *msg);
-
-/**
- * Demultiplex an encapsulated KX message by message type.
- *
- * @param t Tunnel on which the message came.
- * @param message KX message itself.
- */
-void
-GMT_handle_kx (struct CadetTunnel3 *t,
- const struct GNUNET_MessageHeader *message);
-
-/**
- * @brief Use the given path for the tunnel.
- * Update the next and prev hops (and RCs).
- * (Re)start the path refresh in case the tunnel is locally owned.
- *
- * @param t Tunnel to update.
- * @param p Path to use.
- *
- * @return Connection created.
- */
-struct CadetConnection *
-GMT_use_path (struct CadetTunnel3 *t, struct CadetPeerPath *p);
-
-/**
- * Count established (ready) connections of a tunnel.
- *
- * @param t Tunnel on which to count.
- *
- * @return Number of connections.
- */
-unsigned int
-GMT_count_connections (struct CadetTunnel3 *t);
-
-/**
- * Count channels of a tunnel.
- *
- * @param t Tunnel on which to count.
- *
- * @return Number of channels.
- */
-unsigned int
-GMT_count_channels (struct CadetTunnel3 *t);
-
-/**
- * Get the connectivity state of a tunnel.
- *
- * @param t Tunnel.
- *
- * @return Tunnel's connectivity state.
- */
-enum CadetTunnel3CState
-GMT_get_cstate (struct CadetTunnel3 *t);
-
-/**
- * Get the encryption state of a tunnel.
- *
- * @param t Tunnel.
- *
- * @return Tunnel's encryption state.
- */
-enum CadetTunnel3EState
-GMT_get_estate (struct CadetTunnel3 *t);
-
-/**
- * Get the maximum buffer space for a tunnel towards a local client.
- *
- * @param t Tunnel.
- *
- * @return Biggest buffer space offered by any channel in the tunnel.
- */
-unsigned int
-GMT_get_channels_buffer (struct CadetTunnel3 *t);
-
-/**
- * Get the total buffer space for a tunnel for P2P traffic.
- *
- * @param t Tunnel.
- *
- * @return Buffer space offered by all connections in the tunnel.
- */
-unsigned int
-GMT_get_connections_buffer (struct CadetTunnel3 *t);
-
-/**
- * Get the tunnel's destination.
- *
- * @param t Tunnel.
- *
- * @return ID of the destination peer.
- */
-const struct GNUNET_PeerIdentity *
-GMT_get_destination (struct CadetTunnel3 *t);
-
-/**
- * Get the tunnel's next free Channel ID.
- *
- * @param t Tunnel.
- *
- * @return ID of a channel free to use.
- */
-CADET_ChannelNumber
-GMT_get_next_chid (struct CadetTunnel3 *t);
-
-/**
- * Send ACK on one or more channels due to buffer in connections.
- *
- * @param t Channel which has some free buffer space.
- */
-void
-GMT_unchoke_channels (struct CadetTunnel3 *t);
-
-/**
- * Send ACK on one or more connections due to buffer space to the client.
- *
- * Iterates all connections of the tunnel and sends ACKs appropriately.
- *
- * @param t Tunnel which has some free buffer space.
- */
-void
-GMT_send_connection_acks (struct CadetTunnel3 *t);
-
-/**
- * Cancel a previously sent message while it's in the queue.
- *
- * ONLY can be called before the continuation given to the send function
- * is called. Once the continuation is called, the message is no longer in the
- * queue.
- *
- * @param q Handle to the queue.
- */
-void
-GMT_cancel (struct CadetTunnel3Queue *q);
-
-/**
- * Sends an already built message on a tunnel, encrypting it and
- * choosing the best connection.
- *
- * @param message Message to send. Function modifies it.
- * @param t Tunnel on which this message is transmitted.
- * @param c Connection to use (autoselect if NULL).
- * @param force Force the tunnel to take the message (buffer overfill).
- * @param cont Continuation to call once message is really sent.
- * @param cont_cls Closure for @c cont.
- *
- * @return Handle to cancel message. NULL if @c cont is NULL.
- */
-struct CadetTunnel3Queue *
-GMT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
- struct CadetTunnel3 *t, struct CadetConnection *c,
- int force, GMT_sent cont, void *cont_cls);
-
-/**
- * Is the tunnel directed towards the local peer?
- *
- * @param t Tunnel.
- *
- * @return #GNUNET_YES if it is loopback.
- */
-int
-GMT_is_loopback (const struct CadetTunnel3 *t);
-
-/**
- * Is the tunnel using this path already?
- *
- * @param t Tunnel.
- * @param p Path.
- *
- * @return #GNUNET_YES a connection uses this path.
- */
-int
-GMT_is_path_used (const struct CadetTunnel3 *t, const struct CadetPeerPath *p);
-
-/**
- * Get a cost of a path for a tunnel considering existing connections.
- *
- * @param t Tunnel.
- * @param path Candidate path.
- *
- * @return Cost of the path (path length + number of overlapping nodes)
- */
-unsigned int
-GMT_get_path_cost (const struct CadetTunnel3 *t,
- const struct CadetPeerPath *path);
-
-/**
- * Get the static string for the peer this tunnel is directed.
- *
- * @param t Tunnel.
- *
- * @return Static string the destination peer's ID.
- */
-const char *
-GMT_2s (const struct CadetTunnel3 *t);
-
-/**
- * Log all possible info about the tunnel state.
- *
- * @param t Tunnel to debug.
- */
-void
-GMT_debug (const struct CadetTunnel3 *t);
-
-/**
- * Iterate all tunnels.
- *
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GMT_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls);
-
-/**
- * Count all tunnels.
- *
- * @return Number of tunnels to remote peers kept by this peer.
- */
-unsigned int
-GMT_count_all (void);
-
-/**
- * Iterate all connections of a tunnel.
- *
- * @param t Tunnel whose connections to iterate.
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GMT_iterate_connections (struct CadetTunnel3 *t, GMT_conn_iter iter, void
*cls);
-
-/**
- * Iterate all channels of a tunnel.
- *
- * @param t Tunnel whose channels to iterate.
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GMT_iterate_channels (struct CadetTunnel3 *t, GMT_chan_iter iter, void *cls);
-
-#if 0 /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_CADET_SERVICE_TUNNEL_H */
-#endif
-/* end of gnunet-cadet-service_tunnel.h */
Deleted: gnunet/src/mesh/loopcheck.sh
===================================================================
--- gnunet/src/mesh/loopcheck.sh 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/loopcheck.sh 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,8 +0,0 @@
-#!/bin/sh
-
-while true; do
- date;
- taskset 1 make check || break;
- grep -B 10 Assert *log && break
- ls core* &> /dev/null && break
-done
Deleted: gnunet/src/mesh/mesh.conf.in
===================================================================
--- gnunet/src/mesh/mesh.conf.in 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/mesh.conf.in 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,21 +0,0 @@
-[mesh]
-AUTOSTART = @AUTOSTART@
address@hidden@PORT = 2096
-HOSTNAME = localhost
-BINARY = gnunet-service-mesh
-ACCEPT_FROM = 127.0.0.1;
-ACCEPT_FROM6 = ::1;
-UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-mesh.sock
-UNIX_MATCH_UID = YES
-UNIX_MATCH_GID = YES
-REFRESH_CONNECTION_TIME = 5 min
-ID_ANNOUNCE_TIME = 1 h
-APP_ANNOUNCE_TIME = 1 h
-CONNECT_TIMEOUT = 30 s
-DEFAULT_TTL = 64
-DHT_REPLICATION_LEVEL = 3
-MAX_TUNNELS = 1000
-# MAX_TUNNELS deprecated
-MAX_CONNECTIONS = 1000
-MAX_MSGS_QUEUE = 10000
-MAX_PEERS = 1000
Deleted: gnunet/src/mesh/profiler.conf
===================================================================
--- gnunet/src/mesh/profiler.conf 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/profiler.conf 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,19 +0,0 @@
address@hidden@ test_mesh.conf
-
-[testbed]
-OVERLAY_TOPOLOGY = RANDOM
-OVERLAY_RANDOM_LINKS = %LINKS%
-MAX_PARALLEL_SERVICE_CONNECTIONS=4000
-SETUP_TIMEOUT = 60 m
-
-[transport]
-#MANIPULATE_DELAY_IN = 50 ms
-MANIPULATE_DELAY_OUT = 10 ms
-
-[mesh]
-REFRESH_CONNECTION_TIME = 1 h
-DISABLE_TRY_CONNECT = YES
-ID_ANNOUNCE_TIME = 240 s
-
-[dht]
-FORCE_NSE = %NSE%
Deleted: gnunet/src/mesh/run_profiler.sh
===================================================================
--- gnunet/src/mesh/run_profiler.sh 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/run_profiler.sh 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,25 +0,0 @@
-#!/bin/sh
-
-if [ "$#" -lt "3" ]; then
- echo "usage: $0 ROUND_TIME PEERS PINGING_PEERS";
- echo "example: $0 30s 16 1";
- exit 1;
-fi
-
-ROUNDTIME=$1
-PEERS=$2
-PINGS=$3
-
-if [ $PEERS -eq 1 ]; then
- echo "cannot run 1 peer";
- exit 1;
-fi
-
-LINKS=`echo "l($PEERS)/l(2) * $PEERS" | bc -l`
-LINKS=`printf "%.0f" $LINKS`
-NSE=`echo "l($PEERS)/l(2)" | bc -l`
-echo "using $PEERS peers, $LINKS links";
-
-sed -e "s/%LINKS%/$LINKS/;s/%NSE%/$NSE/" profiler.conf > .profiler.conf
-
-./gnunet-mesh-profiler $ROUNDTIME $PEERS $PINGS $4 |& tee log | grep -v DEBUG
Deleted: gnunet/src/mesh/small.dat
===================================================================
--- gnunet/src/mesh/small.dat 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/small.dat 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,21 +0,0 @@
-16
-1:2
-1:9
-2:3
-3:4
-3:11
-4:5
-5:6
-5:13
-6:7
-7:8
-7:15
-8:9
-9:10
-10:11
-11:12
-12:13
-13:14
-14:15
-15:16
-16:1
Deleted: gnunet/src/mesh/test_cadet.c
===================================================================
--- gnunet/src/mesh/test_cadet.c 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/test_cadet.c 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,953 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2011 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-/**
- * @file cadet/test_cadet.c
- *
- * @brief Test for the cadet service: retransmission of traffic.
- */
-#include <stdio.h>
-#include "platform.h"
-#include "cadet_test_lib.h"
-#include "gnunet_cadet_service.h"
-#include "gnunet_statistics_service.h"
-#include <gauger.h>
-
-
-/**
- * How namy messages to send
- */
-#define TOTAL_PACKETS 100
-
-/**
- * How long until we give up on connecting the peers?
- */
-#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
-
-/**
- * Time to wait for stuff that should be rather fast
- */
-#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
-
-/**
- * DIFFERENT TESTS TO RUN
- */
-#define SETUP 0
-#define FORWARD 1
-#define KEEPALIVE 2
-#define SPEED 3
-#define SPEED_ACK 4
-#define SPEED_REL 8
-#define P2P_SIGNAL 10
-
-/**
- * Which test are we running?
- */
-static int test;
-
-/**
- * String with test name
- */
-char *test_name;
-
-/**
- * Flag to send traffic leaf->root in speed tests to test BCK_ACK logic.
- */
-static int test_backwards = GNUNET_NO;
-
-/**
- * How many events have happened
- */
-static int ok;
-
-/**
- * Number of events expected to conclude the test successfully.
- */
-int ok_goal;
-
-/**
- * Size of each test packet
- */
-size_t size_payload = sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t);
-
-/**
- * Operation to get peer ids.
- */
-struct GNUNET_TESTBED_Operation *t_op[2];
-
-/**
- * Peer ids.
- */
-struct GNUNET_PeerIdentity *p_id[2];
-
-/**
- * Peer ids counter.
- */
-unsigned int p_ids;
-
-/**
- * Is the setup initialized?
- */
-static int initialized;
-
-/**
- * Number of payload packes sent
- */
-static int data_sent;
-
-/**
- * Number of payload packets received
- */
-static int data_received;
-
-/**
- * Number of payload packed explicitly (app level) acknowledged
- */
-static int data_ack;
-
-/**
- * Total number of currently running peers.
- */
-static unsigned long long peers_running;
-
-/**
- * Test context (to shut down).
- */
-struct GNUNET_CADET_TEST_Context *test_ctx;
-
-/**
- * Task called to disconnect peers.
- */
-static GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
-
-/**
- * Task To perform tests
- */
-static GNUNET_SCHEDULER_TaskIdentifier test_task;
-
-/**
- * Task called to shutdown test.
- */
-static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle;
-
-/**
- * Cadet handle for the root peer
- */
-static struct GNUNET_CADET_Handle *h1;
-
-/**
- * Cadet handle for the first leaf peer
- */
-static struct GNUNET_CADET_Handle *h2;
-
-/**
- * Channel handle for the root peer
- */
-static struct GNUNET_CADET_Channel *ch;
-
-/**
- * Channel handle for the dest peer
- */
-static struct GNUNET_CADET_Channel *incoming_ch;
-
-/**
- * Time we started the data transmission (after channel has been established
- * and initilized).
- */
-static struct GNUNET_TIME_Absolute start_time;
-
-/**
- * Peers handle.
- */
-static struct GNUNET_TESTBED_Peer **testbed_peers;
-
-/**
- * Statistics operation handle.
- */
-static struct GNUNET_TESTBED_Operation *stats_op;
-
-/**
- * Keepalives sent.
- */
-static unsigned int ka_sent;
-
-/**
- * Keepalives received.
- */
-static unsigned int ka_received;
-
-
-/**
- * Show the results of the test (banwidth acheived) and log them to GAUGER
- */
-static void
-show_end_data (void)
-{
- static struct GNUNET_TIME_Absolute end_time;
- static struct GNUNET_TIME_Relative total_time;
-
- end_time = GNUNET_TIME_absolute_get();
- total_time = GNUNET_TIME_absolute_get_difference(start_time, end_time);
- FPRINTF (stderr, "\nResults of test \"%s\"\n", test_name);
- FPRINTF (stderr, "Test time %s\n",
- GNUNET_STRINGS_relative_time_to_string (total_time,
- GNUNET_YES));
- FPRINTF (stderr, "Test bandwidth: %f kb/s\n",
- 4 * TOTAL_PACKETS * 1.0 / (total_time.rel_value_us / 1000)); //
4bytes * ms
- FPRINTF (stderr, "Test throughput: %f packets/s\n\n",
- TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000)); //
packets * ms
- GAUGER ("CADET", test_name,
- TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000),
- "packets/s");
-}
-
-
-/**
- * Shut down peergroup, clean up.
- *
- * @param cls Closure (unused).
- * @param tc Task Context.
- */
-static void
-shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n");
- shutdown_handle = GNUNET_SCHEDULER_NO_TASK;
-}
-
-
-/**
- * Disconnect from cadet services af all peers, call shutdown.
- *
- * @param cls Closure (unused).
- * @param tc Task Context.
- */
-static void
-disconnect_cadet_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext
*tc)
-{
- long line = (long) cls;
- unsigned int i;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "disconnecting cadet service of peers, called from line %ld\n",
- line);
- disconnect_task = GNUNET_SCHEDULER_NO_TASK;
- for (i = 0; i < 2; i++)
- {
- GNUNET_TESTBED_operation_done (t_op[i]);
- }
- if (NULL != ch)
- {
- GNUNET_CADET_channel_destroy (ch);
- ch = NULL;
- }
- if (NULL != incoming_ch)
- {
- GNUNET_CADET_channel_destroy (incoming_ch);
- incoming_ch = NULL;
- }
- GNUNET_CADET_TEST_cleanup (test_ctx);
- if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle)
- {
- GNUNET_SCHEDULER_cancel (shutdown_handle);
- }
- shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
-}
-
-
-/**
- * Abort test: schedule disconnect and shutdown immediately
- *
- * @param line Line in the code the abort is requested from (__LINE__).
- */
-static void
-abort_test (long line)
-{
- if (disconnect_task != GNUNET_SCHEDULER_NO_TASK)
- {
- GNUNET_SCHEDULER_cancel (disconnect_task);
- disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
- (void *) line);
- }
-}
-
-/**
- * Transmit ready callback.
- *
- * @param cls Closure (message type).
- * @param size Size of the tranmist buffer.
- * @param buf Pointer to the beginning of the buffer.
- *
- * @return Number of bytes written to buf.
- */
-static size_t
-tmt_rdy (void *cls, size_t size, void *buf);
-
-
-/**
- * Task to schedule a new data transmission.
- *
- * @param cls Closure (peer #).
- * @param tc Task Context.
- */
-static void
-data_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct GNUNET_CADET_TransmitHandle *th;
- struct GNUNET_CADET_Channel *channel;
-
- if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
- return;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data task\n");
- if (GNUNET_YES == test_backwards)
- {
- channel = incoming_ch;
- }
- else
- {
- channel = ch;
- }
- th = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
- GNUNET_TIME_UNIT_FOREVER_REL,
- size_payload, &tmt_rdy, (void *) 1L);
- if (NULL == th)
- {
- unsigned long i = (unsigned long) cls;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Retransmission\n");
- if (0 == i)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, " in 1 ms\n");
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
- &data_task, (void *)1UL);
- }
- else
- {
- i++;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "in %u ms\n", i);
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(
- GNUNET_TIME_UNIT_MILLISECONDS,
- i),
- &data_task, (void *)i);
- }
- }
-}
-
-
-/**
- * Transmit ready callback
- *
- * @param cls Closure (message type).
- * @param size Size of the buffer we have.
- * @param buf Buffer to copy data to.
- */
-size_t
-tmt_rdy (void *cls, size_t size, void *buf)
-{
- struct GNUNET_MessageHeader *msg = buf;
- uint32_t *data;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "tmt_rdy called, filling buffer\n");
- if (size < size_payload || NULL == buf)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "size %u, buf %p, data_sent %u, data_received %u\n",
- size, buf, data_sent, data_received);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ok %u, ok goal %u\n", ok, ok_goal);
- GNUNET_break (ok >= ok_goal - 2);
-
- return 0;
- }
- msg->size = htons (size);
- msg->type = htons ((long) cls);
- data = (uint32_t *) &msg[1];
- *data = htonl (data_sent);
- if (GNUNET_NO == initialized)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "sending initializer\n");
- }
- else if (SPEED == test)
- {
- data_sent++;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- " Sent packet %d\n", data_sent);
- if (data_sent < TOTAL_PACKETS)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- " Scheduling packet %d\n", data_sent + 1);
- GNUNET_SCHEDULER_add_now (&data_task, NULL);
- }
- }
-
- return size_payload;
-}
-
-
-/**
- * Function is called whenever a message is received.
- *
- * @param cls closure (set from GNUNET_CADET_connect)
- * @param channel connection to the other end
- * @param channel_ctx place to store local state associated with the channel
- * @param message the actual message
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-int
-data_callback (void *cls, struct GNUNET_CADET_Channel *channel,
- void **channel_ctx,
- const struct GNUNET_MessageHeader *message)
-{
- long client = (long) cls;
- long expected_target_client;
- uint32_t *data;
-
- ok++;
-
- GNUNET_CADET_receive_done (channel);
-
- if ((ok % 20) == 0)
- {
- if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
- {
- GNUNET_SCHEDULER_cancel (disconnect_task);
- disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
- &disconnect_cadet_peers,
- (void *) __LINE__);
- }
- }
-
- switch (client)
- {
- case 0L:
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message!\n");
- break;
- case 4L:
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Leaf client %li got a message.\n",
- client);
- break;
- default:
- GNUNET_assert (0);
- break;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: (%d/%d)\n", ok, ok_goal);
- data = (uint32_t *) &message[1];
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, " payload: (%u)\n", ntohl (*data));
- if (SPEED == test && GNUNET_YES == test_backwards)
- {
- expected_target_client = 0L;
- }
- else
- {
- expected_target_client = 4L;
- }
-
- if (GNUNET_NO == initialized)
- {
- initialized = GNUNET_YES;
- start_time = GNUNET_TIME_absolute_get ();
- if (SPEED == test)
- {
- GNUNET_assert (4L == client);
- GNUNET_SCHEDULER_add_now (&data_task, NULL);
- return GNUNET_OK;
- }
- }
-
- if (client == expected_target_client) // Normally 4
- {
- data_received++;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received data %u\n", data_received);
- if (SPEED != test || (ok_goal - 2) == ok)
- {
- GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
- GNUNET_TIME_UNIT_FOREVER_REL,
- size_payload, &tmt_rdy, (void *) 1L);
- return GNUNET_OK;
- }
- else
- {
- if (data_received < TOTAL_PACKETS)
- return GNUNET_OK;
- }
- }
- else // Normally 0
- {
- if (test == SPEED_ACK || test == SPEED)
- {
- data_ack++;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received ack %u\n", data_ack);
- GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
- GNUNET_TIME_UNIT_FOREVER_REL,
- size_payload, &tmt_rdy, (void *) 1L);
- if (data_ack < TOTAL_PACKETS && SPEED != test)
- return GNUNET_OK;
- if (ok == 2 && SPEED == test)
- return GNUNET_OK;
- show_end_data();
- }
- if (test == P2P_SIGNAL)
- {
- GNUNET_CADET_channel_destroy (incoming_ch);
- incoming_ch = NULL;
- }
- else
- {
- GNUNET_CADET_channel_destroy (ch);
- ch = NULL;
- }
- }
-
- if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
- {
- GNUNET_SCHEDULER_cancel (disconnect_task);
- disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
- &disconnect_cadet_peers,
- (void *) __LINE__);
- }
-
- return GNUNET_OK;
-}
-
-
-/**
- * Stats callback. Finish the stats testbed operation and when all stats have
- * been iterated, shutdown the test.
- *
- * @param cls closure
- * @param op the operation that has been finished
- * @param emsg error message in case the operation has failed; will be NULL if
- * operation has executed successfully.
- */
-static void
-stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "stats_cont for peer %u\n", cls);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, " sent: %u, received: %u\n",
- ka_sent, ka_received);
- if (ka_sent < 2 || ka_sent > ka_received + 1)
- ok--;
- GNUNET_TESTBED_operation_done (stats_op);
-
- if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
- GNUNET_SCHEDULER_cancel (disconnect_task);
- disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
- (void *) __LINE__);
-
-}
-
-
-/**
- * Process statistic values.
- *
- * @param cls closure
- * @param peer the peer the statistic belong to
- * @param subsystem name of subsystem that created the statistic
- * @param name the name of the datum
- * @param value the current value
- * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
- * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
- */
-static int
-stats_iterator (void *cls, const struct GNUNET_TESTBED_Peer *peer,
- const char *subsystem, const char *name,
- uint64_t value, int is_persistent)
-{
- static const char *s_sent = "# keepalives sent";
- static const char *s_recv = "# keepalives received";
- uint32_t i;
-
- i = GNUNET_TESTBED_get_index (peer);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %u - %s [%s]: %llu\n",
- i, subsystem, name, value);
- if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i)
- ka_sent = value;
-
- if (0 == strncmp(s_recv, name, strlen (s_recv)) && 4 == i)
- ka_received = value;
-
- return GNUNET_OK;
-}
-
-
-/**
- * Task check that keepalives were sent and received.
- *
- * @param cls Closure (NULL).
- * @param tc Task Context.
- */
-static void
-check_keepalives (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
- return;
-
- disconnect_task = GNUNET_SCHEDULER_NO_TASK;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "check keepalives\n");
- GNUNET_CADET_channel_destroy (ch);
- stats_op = GNUNET_TESTBED_get_statistics (5, testbed_peers,
- "cadet", NULL,
- stats_iterator, stats_cont, NULL);
-}
-
-
-/**
- * Handlers, for diverse services
- */
-static struct GNUNET_CADET_MessageHandler handlers[] = {
- {&data_callback, 1, sizeof (struct GNUNET_MessageHeader)},
- {NULL, 0, 0}
-};
-
-
-/**
- * Method called whenever another peer has added us to a channel
- * the other peer initiated.
- *
- * @param cls Closure.
- * @param channel New handle to the channel.
- * @param initiator Peer that started the channel.
- * @param port Port this channel is connected to.
- * @param options channel option flags
- * @return Initial channel context for the channel
- * (can be NULL -- that's not an error).
- */
-static void *
-incoming_channel (void *cls, struct GNUNET_CADET_Channel *channel,
- const struct GNUNET_PeerIdentity *initiator,
- uint32_t port, enum GNUNET_CADET_ChannelOption options)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Incoming channel from %s to peer %d\n",
- GNUNET_i2s (initiator), (long) cls);
- ok++;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
- if ((long) cls == 4L)
- incoming_ch = channel;
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Incoming channel for unknown client %lu\n", (long) cls);
- GNUNET_break(0);
- }
- if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
- {
- GNUNET_SCHEDULER_cancel (disconnect_task);
- if (KEEPALIVE == test)
- {
- struct GNUNET_TIME_Relative delay;
- delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS , 5);
- disconnect_task =
- GNUNET_SCHEDULER_add_delayed (delay, &check_keepalives, NULL);
- }
- else
- disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
- &disconnect_cadet_peers,
- (void *) __LINE__);
- }
-
- return NULL;
-}
-
-/**
- * Function called whenever an inbound channel is destroyed. Should clean up
- * any associated state.
- *
- * @param cls closure (set from GNUNET_CADET_connect)
- * @param channel connection to the other end (henceforth invalid)
- * @param channel_ctx place where local state associated
- * with the channel is stored
- */
-static void
-channel_cleaner (void *cls, const struct GNUNET_CADET_Channel *channel,
- void *channel_ctx)
-{
- long i = (long) cls;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Incoming channel disconnected at peer %ld\n", i);
- if (4L == i)
- {
- ok++;
- GNUNET_break (channel == incoming_ch);
- incoming_ch = NULL;
- }
- else if (0L == i)
- {
- if (P2P_SIGNAL == test)
- {
- ok ++;
- }
- GNUNET_break (channel == ch);
- ch = NULL;
- }
- else
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Unknown peer! %d\n", i);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
-
- if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
- {
- GNUNET_SCHEDULER_cancel (disconnect_task);
- disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
- (void *) __LINE__);
- }
-
- return;
-}
-
-
-/**
- * START THE TESTCASE ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES.
- *
- * Testcase continues when the root receives confirmation of connected peers,
- * on callback funtion ch.
- *
- * @param cls Closure (unsued).
- * @param tc Task Context.
- */
-static void
-do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- enum GNUNET_CADET_ChannelOption flags;
-
- if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
- return;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test_task\n");
-
- if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
- {
- GNUNET_SCHEDULER_cancel (disconnect_task);
- }
-
- flags = GNUNET_CADET_OPTION_DEFAULT;
- if (SPEED_REL == test)
- {
- test = SPEED;
- flags |= GNUNET_CADET_OPTION_RELIABLE;
- }
- ch = GNUNET_CADET_channel_create (h1, NULL, p_id[1], 1, flags);
-
- disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
- &disconnect_cadet_peers,
- (void *) __LINE__);
- if (KEEPALIVE == test)
- return; /* Don't send any data. */
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending data initializer...\n");
- data_ack = 0;
- data_received = 0;
- data_sent = 0;
- GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
- GNUNET_TIME_UNIT_FOREVER_REL,
- size_payload, &tmt_rdy, (void *) 1L);
-}
-
-/**
- * Callback to be called when the requested peer information is available
- *
- * @param cls the closure from GNUNET_TESTBED_peer_get_information()
- * @param op the operation this callback corresponds to
- * @param pinfo the result; will be NULL if the operation has failed
- * @param emsg error message if the operation has failed;
- * NULL if the operation is successfull
- */
-static void
-pi_cb (void *cls,
- struct GNUNET_TESTBED_Operation *op,
- const struct GNUNET_TESTBED_PeerInformation *pinfo,
- const char *emsg)
-{
- long i = (long) cls;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "id callback for %ld\n", i);
-
- if (NULL == pinfo || NULL != emsg)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg);
- abort_test (__LINE__);
- return;
- }
- p_id[i] = pinfo->result.id;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " id: %s\n", GNUNET_i2s (p_id[i]));
- p_ids++;
- if (p_ids < 2)
- return;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n");
- test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
- &do_test, NULL);
-}
-
-/**
- * test main: start test when all peers are connected
- *
- * @param cls Closure.
- * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
- * @param num_peers Number of peers that are running.
- * @param peers Array of peers.
- * @param cadetes Handle to each of the CADETs of the peers.
- */
-static void
-tmain (void *cls,
- struct GNUNET_CADET_TEST_Context *ctx,
- unsigned int num_peers,
- struct GNUNET_TESTBED_Peer **peers,
- struct GNUNET_CADET_Handle **cadetes)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n");
- ok = 0;
- test_ctx = ctx;
- peers_running = num_peers;
- testbed_peers = peers;
- h1 = cadetes[0];
- h2 = cadetes[num_peers - 1];
- disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
- &disconnect_cadet_peers,
- (void *) __LINE__);
- shutdown_handle = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
- &shutdown_task, NULL);
- t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0],
- GNUNET_TESTBED_PIT_IDENTITY,
- &pi_cb, (void *) 0L);
- t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1],
- GNUNET_TESTBED_PIT_IDENTITY,
- &pi_cb, (void *) 1L);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n");
-}
-
-
-/**
- * Main: start test
- */
-int
-main (int argc, char *argv[])
-{
- initialized = GNUNET_NO;
- static uint32_t ports[2];
- const char *config_file;
-
- GNUNET_log_setup ("test", "DEBUG", NULL);
- config_file = "test_cadet.conf";
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start\n");
- if (strstr (argv[0], "_cadet_forward") != NULL)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "FORWARD\n");
- test = FORWARD;
- test_name = "unicast";
- ok_goal = 4;
- }
- else if (strstr (argv[0], "_cadet_signal") != NULL)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SIGNAL\n");
- test = P2P_SIGNAL;
- test_name = "signal";
- ok_goal = 4;
- }
- else if (strstr (argv[0], "_cadet_speed_ack") != NULL)
- {
- /* Test is supposed to generate the following callbacks:
- * 1 incoming channel (@dest)
- * TOTAL_PACKETS received data packet (@dest)
- * TOTAL_PACKETS received data packet (@orig)
- * 1 received channel destroy (@dest)
- */
- ok_goal = TOTAL_PACKETS * 2 + 2;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n");
- test = SPEED_ACK;
- test_name = "speed ack";
- }
- else if (strstr (argv[0], "_cadet_speed") != NULL)
- {
- /* Test is supposed to generate the following callbacks:
- * 1 incoming channel (@dest)
- * 1 initial packet (@dest)
- * TOTAL_PACKETS received data packet (@dest)
- * 1 received data packet (@orig)
- * 1 received channel destroy (@dest)
- */
- ok_goal = TOTAL_PACKETS + 4;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n");
- if (strstr (argv[0], "_reliable") != NULL)
- {
- test = SPEED_REL;
- test_name = "speed reliable";
- config_file = "test_cadet_drop.conf";
- }
- else
- {
- test = SPEED;
- test_name = "speed";
- }
- }
- else if (strstr (argv[0], "_keepalive") != NULL)
- {
- test = KEEPALIVE;
- /* Test is supposed to generate the following callbacks:
- * 1 incoming channel (@dest)
- * [wait]
- * 1 received channel destroy (@dest)
- */
- ok_goal = 2;
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNKNOWN\n");
- test = SETUP;
- ok_goal = 0;
- }
-
- if (strstr (argv[0], "backwards") != NULL)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "BACKWARDS (LEAF TO ROOT)\n");
- test_backwards = GNUNET_YES;
- GNUNET_asprintf (&test_name, "backwards %s", test_name);
- }
-
- p_ids = 0;
- ports[0] = 1;
- ports[1] = 0;
- GNUNET_CADET_TEST_run ("test_cadet_small",
- config_file,
- 5,
- &tmain,
- NULL, /* tmain cls */
- &incoming_channel,
- &channel_cleaner,
- handlers,
- ports);
-
- if (ok_goal > ok)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "FAILED! (%d/%d)\n", ok, ok_goal);
- return 1;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n");
- return 0;
-}
-
-/* end of test_cadet.c */
-
Deleted: gnunet/src/mesh/test_cadet.conf
===================================================================
--- gnunet/src/mesh/test_cadet.conf 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/test_cadet.conf 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,100 +0,0 @@
-[testbed]
-AUTOSTART = NO
-PORT = 12113
-ACCEPT_FROM = 127.0.0.1;
-HOSTNAME = localhost
-OVERLAY_TOPOLOGY = LINE
-#PREFIX = xterm -geometry 100x85 -T peer1 -e libtool --mode=execute gdb --args
-
-[fs]
-AUTOSTART = NO
-
-[resolver]
-AUTOSTART = NO
-
-[mesh]
-#BINARY = gnunet-service-mesh-enc
-#PREFIX = valgrind --leak-check=full
-#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
-AUTOSTART = NO
-ACCEPT_FROM = 127.0.0.1;
-REFRESH_CONNECTION_TIME = 2 s
-ID_ANNOUNCE_TIME = 5 s
-CONNECT_TIMEOUT = 30 s
-DEFAULT_TTL = 16
-DHT_REPLICATION_LEVEL = 10
-MAX_TUNNELS = 10
-MAX_CONNECTIONS = 10
-MAX_MSGS_QUEUE = 20
-DISABLE_TRY_CONNECT = YES
-
-[dht]
-AUTOSTART = NO
-DISABLE_TRY_CONNECT = YES
-FORCE_NSE = 3
-
-[dhtcache]
-QUOTA = 1 MB
-DATABASE = heap
-
-[transport]
-PLUGINS = udp
-ACCEPT_FROM6 = ::1;
-ACCEPT_FROM = 127.0.0.1;
-NEIGHBOUR_LIMIT = 50
-PORT = 12365
-#MANIPULATE_DELAY_IN = 10 ms
-#MANIPULATE_DELAY_OUT = 10 ms
-
-
-[ats]
-WAN_QUOTA_OUT = 3932160
-WAN_QUOTA_IN = 3932160
-
-[core]
-PORT = 12092
-AUTOSTART = YES
-USE_EPHEMERAL_KEYS = NO
-
-[arm]
-DEFAULTSERVICES = core transport dht mesh statistics
-PORT = 12366
-
-[transport-udp]
-TIMEOUT = 300 s
-PORT = 12368
-
-[gnunetd]
-HOSTKEY = $GNUNET_TEST_HOME/.hostkey
-
-[PATHS]
-GNUNET_TEST_HOME = /tmp/test-mesh/
-
-[dns]
-AUTOSTART = NO
-
-[nse]
-AUTOSTART = NO
-
-[vpn]
-AUTOSTART = NO
-
-[nat]
-RETURN_LOCAL_ADDRESSES = YES
-DISABLEV6 = YES
-USE_LOCALADDR = YES
-
-[gns-helper-service-w32]
-AUTOSTART = NO
-
-[consensus]
-AUTOSTART = NO
-
-[gns]
-AUTOSTART = NO
-
-[statistics]
-AUTOSTART = NO
-
-[peerinfo]
-NO_IO = YES
Deleted: gnunet/src/mesh/test_cadet_drop.conf
===================================================================
--- gnunet/src/mesh/test_cadet_drop.conf 2014-05-07 12:07:02 UTC (rev
33185)
+++ gnunet/src/mesh/test_cadet_drop.conf 2014-05-07 12:07:16 UTC (rev
33186)
@@ -1,4 +0,0 @@
address@hidden@ test_mesh.conf
-
-[mesh]
-DROP_PERCENT = 1
Deleted: gnunet/src/mesh/test_cadet_local.c
===================================================================
--- gnunet/src/mesh/test_cadet_local.c 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/test_cadet_local.c 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,337 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2011 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file cadet/test_cadet_local.c
- * @brief test cadet local: test of cadet channels with just one peer
- * @author Bartlomiej Polot
- */
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_dht_service.h"
-#include "gnunet_testing_lib.h"
-#include "gnunet_cadet_service.h"
-
-struct GNUNET_TESTING_Peer *me;
-
-static struct GNUNET_CADET_Handle *cadet_peer_1;
-
-static struct GNUNET_CADET_Handle *cadet_peer_2;
-
-static struct GNUNET_CADET_Channel *ch;
-
-static int result = GNUNET_OK;
-
-static int got_data = GNUNET_NO;
-
-static GNUNET_SCHEDULER_TaskIdentifier abort_task;
-
-static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
-
-static struct GNUNET_CADET_TransmitHandle *mth;
-
-
-/**
- * Connect to other client and send data
- *
- * @param cls Closue (unused).
- * @param tc TaskContext.
- */
-static void
-do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
-
-
-/**
- * Shutdown nicely
- */
-static void
-do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutdown\n");
- if (GNUNET_SCHEDULER_NO_TASK != abort_task)
- {
- GNUNET_SCHEDULER_cancel (abort_task);
- }
- if (NULL != ch)
- {
- GNUNET_CADET_channel_destroy (ch);
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect client 1\n");
- if (NULL != cadet_peer_1)
- {
- GNUNET_CADET_disconnect (cadet_peer_1);
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect client 2\n");
- if (NULL != cadet_peer_2)
- {
- GNUNET_CADET_disconnect (cadet_peer_2);
- }
-}
-
-
-/**
- * Something went wrong and timed out. Kill everything and set error flag
- */
-static void
-do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ABORT\n");
- result = GNUNET_SYSERR;
- abort_task = GNUNET_SCHEDULER_NO_TASK;
- if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
- {
- GNUNET_SCHEDULER_cancel (shutdown_task);
- shutdown_task = GNUNET_SCHEDULER_NO_TASK;
- }
- do_shutdown (cls, tc);
-}
-
-
-/**
- * Function is called whenever a message is received.
- *
- * @param cls closure (set from GNUNET_CADET_connect)
- * @param channel connection to the other end
- * @param channel_ctx place to store local state associated with the channel
- * @param message the actual message
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-static int
-data_callback (void *cls, struct GNUNET_CADET_Channel *channel,
- void **channel_ctx,
- const struct GNUNET_MessageHeader *message)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data callback! Shutting down.\n");
- got_data = GNUNET_YES;
- if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
- GNUNET_SCHEDULER_cancel (shutdown_task);
- shutdown_task =
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_shutdown,
- NULL);
- GNUNET_CADET_receive_done (channel);
- return GNUNET_OK;
-}
-
-
-/**
- * Method called whenever another peer has added us to a channel
- * the other peer initiated.
- *
- * @param cls closure
- * @param channel new handle to the channel
- * @param initiator peer that started the channel
- * @param port port number
- * @param options channel options
- * @return initial channel context for the channel
- * (can be NULL -- that's not an error)
- */
-static void *
-inbound_channel (void *cls, struct GNUNET_CADET_Channel *channel,
- const struct GNUNET_PeerIdentity *initiator,
- uint32_t port, enum GNUNET_CADET_ChannelOption options)
-{
- long id = (long) cls;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "received incoming channel on peer %d, port %u\n",
- id, port);
- if (id != 2L)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "wrong peer\n");
- result = GNUNET_SYSERR;
- }
- return NULL;
-}
-
-
-/**
- * Function called whenever an channel is destroyed. Should clean up
- * any associated state.
- *
- * @param cls closure (set from GNUNET_CADET_connect)
- * @param channel connection to the other end (henceforth invalid)
- * @param channel_ctx place where local state associated
- * with the channel is stored
- */
-static void
-channel_end (void *cls, const struct GNUNET_CADET_Channel *channel,
- void *channel_ctx)
-{
- long id = (long) cls;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "incoming channel closed at peer %ld\n",
- id);
- if (NULL != mth)
- {
- GNUNET_CADET_notify_transmit_ready_cancel (mth);
- mth = NULL;
- }
- if (GNUNET_NO == got_data)
- {
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (
- GNUNET_TIME_UNIT_SECONDS,
- 2),
- &do_connect, NULL);
- }
-}
-
-
-/**
- * Handler array for traffic received on peer1
- */
-static struct GNUNET_CADET_MessageHandler handlers1[] = {
- {&data_callback, 1, 0},
- {NULL, 0, 0}
-};
-
-
-/**
- * Handler array for traffic received on peer2 (none expected)
- */
-static struct GNUNET_CADET_MessageHandler handlers2[] = {
- {&data_callback, 1, 0},
- {NULL, 0, 0}
-};
-
-
-/**
- * Data send callback: fillbuffer with test packet.
- *
- * @param cls Closure (unused).
- * @param size Buffer size.
- * @param buf Buffer to fill.
- *
- * @return size of test packet.
- */
-static size_t
-do_send (void *cls, size_t size, void *buf)
-{
- struct GNUNET_MessageHeader *m = buf;
-
- mth = NULL;
- if (NULL == buf)
- {
- GNUNET_break (0);
- result = GNUNET_SYSERR;
- return 0;
- }
- m->size = htons (sizeof (struct GNUNET_MessageHeader));
- m->type = htons (1);
- GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
- return sizeof (struct GNUNET_MessageHeader);
-}
-
-/**
- * Connect to other client and send data
- *
- * @param cls Closue (unused).
- * @param tc TaskContext.
- */
-static void
-do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct GNUNET_PeerIdentity id;
-
- if (NULL != tc && 0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
- return;
-
- GNUNET_TESTING_peer_get_identity (me, &id);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CONNECT BY PORT\n");
- ch = GNUNET_CADET_channel_create (cadet_peer_1, NULL, &id, 1,
- GNUNET_CADET_OPTION_DEFAULT);
- mth = GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
- GNUNET_TIME_UNIT_FOREVER_REL,
- sizeof (struct
GNUNET_MessageHeader),
- &do_send, NULL);
-}
-
-
-/**
- * Initialize framework and start test
- *
- * @param cls Closure (unused).
- * @param cfg Configuration handle.
- * @param peer Testing peer handle.
- */
-static void
-run (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg,
- struct GNUNET_TESTING_Peer *peer)
-{
- static uint32_t ports[] = {1, 0};
-
- me = peer;
- abort_task =
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS, 15), &do_abort,
- NULL);
- cadet_peer_1 = GNUNET_CADET_connect (cfg, /* configuration */
- (void *) 1L, /* cls */
- NULL, /* inbound new hndlr */
- &channel_end, /* channel end hndlr */
- handlers1, /* traffic handlers */
- NULL); /* ports offered */
-
- cadet_peer_2 = GNUNET_CADET_connect (cfg, /* configuration */
- (void *) 2L, /* cls */
- &inbound_channel, /* inbound new hndlr
*/
- &channel_end, /* channel end hndlr */
- handlers2, /* traffic handlers */
- ports); /* ports offered */
- if (NULL == cadet_peer_1 || NULL == cadet_peer_2)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Couldn't connect to cadet :(\n");
- result = GNUNET_SYSERR;
- return;
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "YAY! CONNECTED TO CADET :D\n");
- }
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (
- GNUNET_TIME_UNIT_SECONDS,
- 2),
- &do_connect, NULL);
-}
-
-
-/**
- * Main
- */
-int
-main (int argc, char *argv[])
-{
- if (0 != GNUNET_TESTING_peer_run ("test-cadet-local",
- "test_cadet.conf",
- &run, NULL))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "run failed\n");
- return 2;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Final result: %d\n", result);
- return (result == GNUNET_OK) ? 0 : 1;
-}
-
-/* end of test_cadet_local_1.c */
Deleted: gnunet/src/mesh/test_cadet_single.c
===================================================================
--- gnunet/src/mesh/test_cadet_single.c 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/test_cadet_single.c 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,329 +0,0 @@
-/*
- This file is part of GNUnet.
- (C) 2011 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * @file cadet/test_cadet_single.c
- * @brief test cadet single: test of cadet channels with just one client
- * @author Bartlomiej Polot
- */
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_dht_service.h"
-#include "gnunet_testing_lib.h"
-#include "gnunet_cadet_service.h"
-
-#define REPETITIONS 5
-#define DATA_SIZE 35000
-
-struct GNUNET_TESTING_Peer *me;
-
-static struct GNUNET_CADET_Handle *cadet;
-
-static struct GNUNET_CADET_Channel *ch1;
-
-static struct GNUNET_CADET_Channel *ch2;
-
-static int result;
-
-static GNUNET_SCHEDULER_TaskIdentifier abort_task;
-
-static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
-
-static unsigned int repetition;
-
-
-/* forward declaration */
-static size_t
-do_send (void *cls, size_t size, void *buf);
-
-
-/**
- * Shutdown nicely
- */
-static void
-do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutdown\n");
- if (GNUNET_SCHEDULER_NO_TASK != abort_task)
- {
- GNUNET_SCHEDULER_cancel (abort_task);
- }
- if (NULL != ch1)
- {
- GNUNET_CADET_channel_destroy (ch1);
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect client 1\n");
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect client 2\n");
- if (NULL != cadet)
- {
- GNUNET_CADET_disconnect (cadet);
- cadet = NULL;
- }
- else
- {
- GNUNET_break (0);
- }
-}
-
-
-/**
- * Something went wrong and timed out. Kill everything and set error flag
- */
-static void
-do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ABORT\n");
- result = GNUNET_SYSERR;
- abort_task = GNUNET_SCHEDULER_NO_TASK;
- if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
- {
- GNUNET_SCHEDULER_cancel (shutdown_task);
- shutdown_task = GNUNET_SCHEDULER_NO_TASK;
- }
- do_shutdown (cls, tc);
-}
-
-
-static void
-finish (void)
-{
- if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
- GNUNET_SCHEDULER_cancel (shutdown_task);
- shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
- &do_shutdown, NULL);
-}
-
-
-/**
- * Function is called whenever a message is received.
- *
- * @param cls closure (set from GNUNET_CADET_connect)
- * @param channel connection to the other end
- * @param channel_ctx place to store local state associated with the channel
- * @param message the actual message
- *
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- */
-static int
-data_callback (void *cls, struct GNUNET_CADET_Channel *channel,
- void **channel_ctx,
- const struct GNUNET_MessageHeader *message)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Data callback! Repetition %u/%u\n",
- repetition, REPETITIONS);
- repetition = repetition + 1;
- if (repetition < REPETITIONS)
- {
- struct GNUNET_CADET_Channel *my_channel;
- if (repetition % 2 == 0)
- my_channel = ch1;
- else
- my_channel = ch2;
- GNUNET_CADET_notify_transmit_ready (my_channel, GNUNET_NO,
- GNUNET_TIME_UNIT_FOREVER_REL,
- sizeof (struct GNUNET_MessageHeader)
- + DATA_SIZE,
- &do_send, NULL);
- GNUNET_CADET_receive_done (channel);
- return GNUNET_OK;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All data OK. Destroying channel.\n");
- GNUNET_CADET_channel_destroy (ch1);
- ch1 = NULL;
- return GNUNET_OK;
-}
-
-
-/**
- * Method called whenever another peer has added us to a channel
- * the other peer initiated.
- *
- * @param cls closure
- * @param channel new handle to the channel
- * @param initiator peer that started the channel
- * @param port port number
- * @param options channel option flags
- * @return initial channel context for the channel
- * (can be NULL -- that's not an error)
- */
-static void *
-inbound_channel (void *cls, struct GNUNET_CADET_Channel *channel,
- const struct GNUNET_PeerIdentity *initiator,
- uint32_t port, enum GNUNET_CADET_ChannelOption options)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "received incoming channel on port %u\n",
- port);
- ch2 = channel;
- return NULL;
-}
-
-
-/**
- * Function called whenever an inbound channel is destroyed. Should clean up
- * any associated state.
- *
- * @param cls closure (set from GNUNET_CADET_connect)
- * @param channel connection to the other end (henceforth invalid)
- * @param channel_ctx place where local state associated
- * with the channel is stored
- */
-static void
-channel_end (void *cls, const struct GNUNET_CADET_Channel *channel,
- void *channel_ctx)
-{
- long id = (long) cls;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "incoming channel closed at peer %ld\n",
- id);
- if (REPETITIONS == repetition && channel == ch2)
- {
- ch2 = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "everything fine! finishing!\n");
- result = GNUNET_OK;
- finish ();
- }
-}
-
-
-/**
- * Handler array for traffic received on peer1
- */
-static struct GNUNET_CADET_MessageHandler handlers1[] = {
- {&data_callback, 1, 0},
- {NULL, 0, 0}
-};
-
-
-/**
- * Data send callback: fillbuffer with test packet.
- *
- * @param cls Closure (unused).
- * @param size Buffer size.
- * @param buf Buffer to fill.
- *
- * @return size of test packet.
- */
-static size_t
-do_send (void *cls, size_t size, void *buf)
-{
- struct GNUNET_MessageHeader *m = buf;
-
- if (NULL == buf)
- {
- GNUNET_break (0);
- result = GNUNET_SYSERR;
- return 0;
- }
- m->size = htons (sizeof (struct GNUNET_MessageHeader));
- m->type = htons (1);
- memset (&m[1], 0, DATA_SIZE);
- GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader) + DATA_SIZE);
- return sizeof (struct GNUNET_MessageHeader) + DATA_SIZE;
-}
-
-/**
- * Connect to other client and send data
- *
- * @param cls Closue (unused).
- * @param tc TaskContext.
- */
-static void
-do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct GNUNET_PeerIdentity id;
- size_t size = sizeof (struct GNUNET_MessageHeader) + DATA_SIZE;
-
- if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
- return;
-
- GNUNET_TESTING_peer_get_identity (me, &id);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CONNECT BY PORT\n");
- ch1 = GNUNET_CADET_channel_create (cadet, NULL, &id, 1,
- GNUNET_CADET_OPTION_DEFAULT);
- GNUNET_CADET_notify_transmit_ready (ch1, GNUNET_NO,
- GNUNET_TIME_UNIT_FOREVER_REL,
- size, &do_send, NULL);
-}
-
-
-/**
- * Initialize framework and start test
- *
- * @param cls Closure (unused).
- * @param cfg Configuration handle.
- * @param peer Testing peer handle.
- */
-static void
-run (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg,
- struct GNUNET_TESTING_Peer *peer)
-{
- static uint32_t ports[] = {1, 0};
-
- me = peer;
- abort_task =
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS, 15), &do_abort,
- NULL);
- cadet = GNUNET_CADET_connect (cfg, /* configuration */
- (void *) 1L, /* cls */
- &inbound_channel, /* inbound new hndlr */
- &channel_end, /* inbound end hndlr */
- handlers1, /* traffic handlers */
- ports); /* ports offered */
-
- if (NULL == cadet)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Couldn't connect to cadet :(\n");
- result = GNUNET_SYSERR;
- return;
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "YAY! CONNECTED TO CADET :D\n");
- }
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_connect, NULL);
-}
-
-
-/**
- * Main
- */
-int
-main (int argc, char *argv[])
-{
- result = GNUNET_NO;
- if (0 != GNUNET_TESTING_peer_run ("test-cadet-local",
- "test_cadet.conf",
- &run, NULL))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "run failed\n");
- return 2;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Final result: %d\n", result);
- return (result == GNUNET_OK) ? 0 : 1;
-}
-
-/* end of test_cadet_single.c */
Deleted: gnunet/src/mesh/valgrind-mesh.supp
===================================================================
--- gnunet/src/mesh/valgrind-mesh.supp 2014-05-07 12:07:02 UTC (rev 33185)
+++ gnunet/src/mesh/valgrind-mesh.supp 2014-05-07 12:07:16 UTC (rev 33186)
@@ -1,116 +0,0 @@
-{
- logsetup_addr
- Memcheck:Addr8
- obj:/lib/libc-2.14.1.so
- ...
- fun:get_type
- fun:GNUNET_log_setup
- fun:GNUNET_SERVICE_run
- fun:main
-}
-
-{
- scanf_addr
- Memcheck:Addr8
- obj:/lib/libc-2.14.1.so
- ...
- fun:vsscanf
- fun:sscanf
- fun:GNUNET_CONFIGURATION_get_value_number
- fun:GNUNET_SERVICE_get_server_addresses
- fun:setup_service
- fun:GNUNET_SERVICE_run
- fun:main
-}
-
-{
- mylog_addr
- Memcheck:Addr8
- obj:/lib/libc-2.14.1.so
- ...
- fun:service_task
- fun:GNUNET_SCHEDULER_run
- fun:GNUNET_SERVICE_run
- fun:main
-}
-
-{
- mylog_uninit
- Memcheck:Value8
- obj:/lib/libc-2.14.1.so
- ...
- fun:mylog
- fun:GNUNET_log_from_nocheck
- fun:service_task
- ...
- fun:GNUNET_SCHEDULER_run
- fun:GNUNET_SERVICE_run
- fun:main
-}
-
-{
- mylog_from_cond
- Memcheck:Cond
- obj:/lib/libc-2.14.1.so
- ...
- fun:mylog
- fun:GNUNET_log_from_nocheck
- ...
- fun:service_task
- fun:GNUNET_SCHEDULER_run
- fun:GNUNET_SERVICE_run
- fun:main
-}
-
-{
- mylog_cond
- Memcheck:Cond
- obj:/lib/libc-2.14.1.so
- ...
- fun:mylog
- fun:GNUNET_log_nocheck
- ...
- fun:service_task
- fun:GNUNET_SCHEDULER_run
- fun:GNUNET_SERVICE_run
- fun:main
-}
-
-{
- inet_ntop_cond
- Memcheck:Cond
- obj:/lib/libc-2.14.1.so
- ...
- fun:inet_ntop
- fun:GNUNET_a2s
- ...
- fun:service_task
- fun:GNUNET_SCHEDULER_run
- fun:GNUNET_SERVICE_run
- fun:main
-}
-
-{
- create_key_from_file
- Memcheck:Addr8
- obj:/lib/libc-2.14.1.so
- ...
- fun:GNUNET_CRYPTO_rsa_key_create_from_file
- fun:run
- fun:service_task
- fun:GNUNET_SCHEDULER_run
- fun:GNUNET_SERVICE_run
- fun:main
-}
-
-{
- main_notify_handler
- Memcheck:Addr8
- obj:/lib/libc-2.14.1.so
- ...
- fun:main_notify_handler
- fun:receive_ready
- fun:GNUNET_SCHEDULER_run
- fun:GNUNET_SERVICE_run
- fun:main
-}
\ No newline at end of file
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r33186 - in gnunet/src: . cadet mesh,
gnunet <=